FlexSim Knowledge Base
Announcements, articles, and guides to help you take your simulations to the next level.
Sort by:
FlexSim 2017 Update 1 Beta is available. (updated 5 Apr 2017) To get the beta, log in to your account at www.flexsim.com, then go to the Downloads section, and click on More Versions. It will be at the top of the list. If you have bug reports or other feedback on the software, please email dev@flexsim.com or create a new idea in the Development space. Release Notes Changed FlexSim to store strings using UTF-8 encoding. Added support for Oculus Touch controllers. Implemented OpenVR for HTC Vive compatibility. Improved the shadow frustum calculation in VR so that shadows look better. Added a global preference for changing the resolution of the shadow map. Added support for nested queries in SQL. Added ROW_NUMBER as a SQL keyword. Implemented F2 and Esc functionality in tables. Updated the table view and labels tab to be more robust with different datatypes. Added Table(name) method for referencing Global Tables. Added more FlexScript classes, including List, AGV, Conveyor, and TrackedVariable. Added more properties and methods to existing FlexScript classes, including Object stats and additional string methods. Improved scientific notation for literals in FlexScript. Added a start value to tracked variables. All tracked variables in the model now reset on model reset. Changed itemtype references to referencing an item's type label instead. Improved the Person flowitem's 3D shape. Added repeating events to time tables. Added a short description field to user commands. Made the gantt charts and time charts scroll with a fixed time window. Removed the global table Clear on Reset checkbox and replaced it with a reset trigger. Added new visualization options for the Rack. Added duplicate buttons to the Excel Interface window. Added a duplicate option to the Toolbox's context menu. Taskbar now shows experimenter/optimizer status and runtime based upon stop time. Disabled deleting objects while the model is running. Fixed an issue with the undo history when pasting over nodes with pointer data. Fixed issues with using the ternary operator after properties. Fixed an issue with writing to Access databases with read-only fields. Included fixes listed in 17.0.3. Backwards Compatibility Note: the following changes may slightly change the way updated models behave. Removed the FlexSim WebServer application from the default installation and developed a new WebServer application using Node.js that streams the 3D view much faster. The new WebServer can be downloaded through FlexSim's Online Content. Existing models will continue to work with itemtype, but new models should be built using a type label instead of the itemtype attribute and commands. Process Flow Added an Assign Released Resource(s) To field on the Release Resource activity. Added functionality to allow you to Ctrl+Drag activities in an activity block. Added a right-click menu option and Alt+Click to open the Token View. Added a sampler to the assign labels Label Name field so you can sample other activities or tokens to get label names. Added a right-click menu option to open multiple views of a Process Flow. Added an Assign To property to the Create Tokens activity. Added a Make Array label aggregation type to the Batch. Added Center in View buttons for fields with pointer data. Added a name property to the Token FlexScript class. Fixed a bug with duplicating Process Flows using the Toolbox. Backwards Compatibility Note: the following changes may slightly change the way updated models behave. Updated the Pull From List activity so it does not assign a null label when nothing was pulled or the token was released early (manually). Previously, if you used a Max Wait Timer or Max Idle Timer (or some other mechanism) to release a token from a Pull from List prematurely, the label specified in the Assign To field would be created with a value of NULL. Now, the label will not be created. This may break other models that are checking to see if the label value exists. For example, saying objectexists(token.pulled) will throw an exception if the pulled label is never created. This can be easily remedied by changing the code to objectexists(token.pulled?). The ? will cause the value returned to be nullvar when the pulled label does not exist. Universal Edit fields are now more strict when accessing labels on a token. Previously, typing token.labelThatDoesNotExist would happily return NULL and move on. Now the Universal Edit will throw an exception if the label doesn't exist. This does not include Universal Edit fields that assert labels, for example the Assign To fields.
View full article
Neste Tutorial iremos demonstrar como funciona a ferramenta Model Layouts no FlexSim. Esta ferramenta permite que você crie e edite diferentes Layouts para um mesmo modelo. Você pode modificar a posição dos objetos e criar uma nova opção de Layout. Por exemplo você pode salvar um Layout inicial de seu processo e após montar propostas a serem estudadas, como um Layout com diferentes posições, redução de transporte, etc... O Model Layouts permite que você possa fazer isso. modellayouts-example-model.fsm Ferramenta útil para estudar comparativamente os resultados gráficos dos Layouts criados apenas rodando o modelo para cada um dos Layouts, e ou para criar a variável Layout para inclusão das opções de Layouts em um experimento. As informações de Layout são armazenadas em cada um dos objetos individuais. Um nó é adicionado aos atributos de objeto chamados Layouts. Para cada Layout criado, uma cópia das informações espaciais atuais do objeto (posição, tamanho, rotação) é armazenada. Janela Model Layout Esta janela pode ser acessada em: View Menu / Model Layouts Layout List - Exibe a lista de Layouts atuais. Selecione um layout para atualizar imediatamente o modelo desse Layout. Você pode renomear um Layout digitando um novo nome neste campo. Add Layout - Adiciona um novo Layout. Quando você adiciona um Layout, ele salva o Layout atual do modelo. Delete Layout - Remove o Layout selecionado. Set - Opção para atualizar o Layout do modelo selecionado para corresponder ao Layout atual do modelo indicado na lista (Layout List).
View full article
One of the most powerful features of Process Flow is the ability to easily define a Task Sequence. However, many real-life situations require the coordination of multiple workers and machines to do a single task. This article demonstrates one approach you can use with Process Flow to coordinate multiple Task Executers, or in other words, to create a coordinated task sequence. This article talks about an example model (handoff.fsm). It might be easiest to open that model, watch it run, and perhaps read this article with the model open. The Example Scenario Here is a screenshot of the demo model used in this article: Items enter the system on the left. The yellow operator must carry each item to the queue in the middle, and then wait for the purple operator to arrive. Once the two operators are both at the middle queue, then the yellow operator can unload the box, and the purple operator can take it. After this point, the yellow operator is free to load another item from the left queue. The purple operator takes the item, waits for a while, and then puts the item in the sink on the right. The interesting part of this model is the hand off. The yellow operator must wait for the purple operator, and vice versa. This is the synchronization point, and it requires coordination of both operators. The approach used in this model allows you to add more operators to the yellow side, and more to the purple side. But it still maintains that a yellow operator must wait for a purple operator before unloading the box. The Example Model In addition to to the 3D layout shown previously, there are 5 process flows in the example model. The first is a general flow, and defines the logic for each task. The second is a Task Executor flow, and defines the logic for the yellow operator. The third is also a Task Executor flow, and defines the logic for the purple operator. The remaining two flows are synchronization flows, for synchronizing between the other three flows. Synchronizing on a Task The basic approach in this model uses the Synchronize activity. This activity waits for one token from each incoming connector, before it allows any of the tokens to move on. Here is the Yellow Purple Sync flow (a global Sub Flow) from the example model: The flows for the yellow and purple operators each use the Run Sub Flow activity to send a token to this flow, to their respective start activities (you can use the sampler on the Run Sub Flow activity to sample a specific start activity in a sub flow). This is what allows both the yellow and purple operators to wait for each other. However, it is important that the yellow and purple operators are both doing the same task. In this model, there is a token that represents each item that needs to be moved. Both operators get a reference to this task token. The Synchronize activity is set up to partition by that Task token. That means that a yellow and purple operators must both call this sub flow with the same task token, ensuring that each task has its own synchronization. In the example model, this kind of synchronization happens between operators, and it happens between each task and an operator. Basically, the task must wait for the operator to finish that operator's part. The Task Flow A task token is created every time an item enters the first queue. The tasks flow puts that task on both the Yellow and Purple lists. In both cases, the task token does not wait to be pulled, but keeps itself on the list. Then, the task token waits for a yellow operator to finish with it, and then for the purple operator to finish with it. There is a zone in this flow, but its only purpose it to gather statistics for how long the whole task took. The Yellow and Purple Flows These flows are easiest to understand when viewed side by side: Recall that each task is put on both the Yellow and Purple lists at the exact same model time. The yellow operator waits to get a task (at the Get Task activity). Then the operator travels to the first queue, gets the item, and travels to the second queue. At this point, the yellow operator waits. At the same time, the purple operator is also waiting for the task. The purple operator just has to travel to the second queue before waiting for the yellow. Once the yellow operator arrives, the purple operator also has to wait for the yellow operator to unload the box. On the yellow side, once the purple operator arrives, the yellow operator unloads the box, and then synchronizes with the purple operator, allowing the purple operator to load the box. Summary The purpose of this article is to show one method for synchronizing token in separate flows. That method is as follows: Have a token for each task. As each task executor (or fixed resource) needs to synchronize, they each use a Run Sub Flow activity, putting the token in a specific Start activity. The Sub Flow (a global Sub Flow) has a synchronize activity, that requires a token from each participant for that task before releasing the tokens. This is certainly not the only way to create this model. However, there are some advantages: By forcing the task to synchronize, you can gather stats on how long each phase of the task took, as well as how long the complete task took. You can add more yellow or purple operators by copy/paste. They simply follow their own logic Each set of logic is separated; tasks, yellow operators, and purple operators each have their own flows, making each one much simpler. The exact approach used in the example model will not work exactly as it is for each model. However, you can apply the general principles, and adapt them to your own situation.
View full article
Post a Question Post your bug report as a question if you want a response from us; for example, if you are looking for a workaround or a fix for your model. When creating your question, consider putting it into the Bug Reports space: Post an Idea You can also post it on this forum as an idea. This lets other users in the community vote on the idea and gives us an idea of how much demand there is. This also creates a place where the idea can be discussed by users and developers. Summary Feature requests and bug reports will be monitored by support and development teams. For confirmed bugs, we will create an issue on our development list. The issue will then be discussed by the developers in our next sprint meeting where we will determine when, relative to the other issues, we want to work on it.
View full article
Nesse exemplo nós vamos construir um modelo que usa listas para relações básicas de roteamento de itens. Os itens serão enviados de três filas para um dos quatro processos. Nós vamos usar uma Lista de itens (item list). As filas irão empurrar os itens para a lista e os processos irão puxar os itens da lista e processa-los. Inicialmente, vamos implementar um simples puxado, mas depois iremos experimentar o puxado com restrições e priorizações. Passo 1. Montar Layout Para esse exemplo, criaremos um novo layout. A Figura 1 mostra quais objetos devem estar presentes nesse layout. Observe que NÃO há ligação entre as filas e os processos. Figura 1- Layout exemplo 2 Passo 2. Configurar source Na janela de propriedades do source, em inter-Arrivaltime coloque exponential (0 ,2.5,0). Figura 2- Inserir inter- arrival time 2.Na aba FLOW, em send to port abra a lista de opções e escolha a opção random port. Figura 3- Sent to port 3.Na aba trigger, adicionar uma Oncreation trigger para configurar o tipo e a cor. OnCreation> Data > Set item type and color Figura 4- Configurar tipo e cor Passo 3. Adicionar lists Para adicionar a lógica é preciso criar um item list. Em Toolbox> > Global list> Item list(Figura 5). Figura 5- Adicionar item list Ao clicar em Item list irá abrir janela de propriedades da lista (Figura 6), por agora apenas feche a aba. A sua lista está nomeada como ItemList1. Figura 6- Janela de propriedades Itemlist Não é necessário definir nenhuma das configurações agora. Apenas feche a janela de propriedades. Passo 4. Configurar queue Para configurar a queue para empurrar os itens para a lista, clique sobre cada uma das filas> Aba Flow> Send to port> abra a lista de opções> Escolha use list> Push to item list. CONFIRA se o o nome da lista corresponde ao nome da lista que você criou. Figura 7- Push to item list OBS: Fazer o Passo 4 para (((TODAS))) as filas Passo 5. Configurar Processos Para fazer com que os processos puxem da lista, nós precisamos configurar cada input de processos para todos os 4 processos. Clique em um dos processos, na aba Flow vá na parte de input, marque a opção pull strategy. Na aba de escolha da estratégia >Use list>Pull from item list. Você pode deixar o campo QUERY em branco. E confira se o nome da lista escolhida é o mesmo da lista que você criou no Passo 3. Figura 8- Estratégia puxada Obs: Não esqueça de fazer o passo 5 para todos os processors. Salve seu modelo como Exemplo 2 e ele está pronto para ser executado. Mas antes de fazer isso vamos dar uma olhada no que está na lista. Para verificar se até aqui as coisas estão funcionando da maneira correta. Vamos fazer um test rápido. Nas propriedades do ItemList1, vá na aba General e clique no botão a esquerda “ Back Orders”, sua lista deve estar parecida com a da Figura 9. Mudando apenas os nomes dos processos de acordo como os seus estão nomeados. Figura 9- Janela de pedidos pendentes A Figura 9 representa que os processos começaram a puxar da lista, mas como não há itens que foram empurrados para a lista, eles estão aguardando para poderem puxar e se tornarem fulfilled(preenchidos). Execute o modelo e você perceberá os itens vão entrar nas filas e serão empurrados para a lista (View entries) fazendo com que os pedidos pendentes sejam atendidos e então começam a ser processados. Quando um item é empurrado para a lista e existe pedidos pendentes o item será imediatamente puxado da lista. Dessa forma o pedido pendente irá se tornar Fulfilled e será removido da lista de pedidos pendentes. Eventualmente, todos os processos irão puxar os itens e dessa forma a lista de pedidos pendentes se tornará vazia, já que todos estão em operação. Então a lista de entradas vai crescendo(Figura 10) até que um dos processos termine o processamento e requisite puxar um item da lista. Figura 10- Entradas na lista aguardando serem puxadas Quando os itens são empurrados para a lista, eles são adicionados no fim da lista. Assim se o sistema puxado não utilizar prioridades como parte da sua tomada de decisão, os itens irão ser puxados como FIFO( first-in-first-out), ou seja, seguindo uma ordem de quem chegou primeiro sai primeiro. O mesmo acontece com os pedidos pendentes pendentes. A primeira máquina que ficar disponível irá puxar o primeiro item que entrar na lista. exemplo2.fsm Experimentos Agora vamos experimentar diferentes configurações das operações puxadas. Cenário 1- Filtrar por tipo de item Vamos considerar que um dos processos pode apenas processar o tipo de item 2. Nós podemos vincular essa lógica na simulação utilizando uma simples Query nesse processo. Clique sobre o processo que deseja restringir a entrada ao tipo 2 de item, na janela de propriedades, vá em FLOW > >Pull strategy >em Query digite a restrição WHERE itemtype == 2 (Figura 11). Figura 11- Adicionar query para tipo de item Salve o modelo como Exemplo2_cenario1. Reset seu modelo e execute. exemplo2-cenario1.fsm Cenário 2- Puxar pelo LIFO Vamos supor que agora queremos que todos os processos puxem seguindo a ordem último a chegar primeiro a sair (LIFO) ao invés do padrão FIFO, o que significa que o item mais recentemente adicionado na lista deve ser o primento a ser puxado da lista. Nós podemos criar essa lógica na simulação, implementando uma simples puxada Query. Abra o arquivo do exemplo 2, e salve como exemplo2_cenario2. Para cada um dos 4 processos faça o seguinte: 1)Clique no processo >vá em FLOW > Pull strategy > em Query digite a restrição ORDER BY age ASC (Figura 12). Figura 12- Lógica LIFO Repita 1) para TODOS os processos. Salve o modelo e coloque para executar. exemplo2-cenario2.fsm Use a ferramenta avançada view entry Nessa ferramenta você pode verificar se o seu modelo está rodando de acordo com a lógica planejada. Por exemplo, se você quiser testar o seu query de order by age asc para você ter certeza de o que você quer antes de implementar no modelo. Você pode usar a ferramenta avançada para fazer isso. Execute o modelo até que tenha um número significativo de itens na lista. Nas propriedades do ItemList1, vá na aba General e clique no botão a esquerda “ View entries”. Pressione botão para mostra as ferramentas avançadas (Figura 13). Figura 13- Ferramentas avançadas view entry Agora teste colocar a Query por ORDER BY age ASC e pressione enter (Figura 14). Figura 14- Itens ordenados por tempo Na Figura 14 você pode notar que os itens na lista estão agora reorganizados com as idades ascendentes. A ordem puxada que usa a query order by age asc, vai puxar do topo dessa lista. No caso o primeiro a ser puxado seria o Queue5/Box~3 com itemtype de 3 e age de 0. 18, o último a entrar na fila.
View full article
Neste Tutorial iremos demonstrar em um exemplo como funciona a biblioteca AStar Navigator no FlexSim. O AStar Navigator, também conhecido como A*, é um algoritmo de busca usado para encontrar um caminho entre pontos, e serve para determinarmos o trajeto pelo qual os executores de tarefas podem se movimentar pelo modelo. Esta biblioteca permite que você crie e defina barreiras físicas para a correta movimentação dos executores de tarefas em seu modelo. Nós iremos usar o seguinte modelo para mostrar como o A* Navigator pode ser usado em um modelo simples. astar-example-model.fsm Crie o A* Navigator Primeiro, um objeto AStarNavigator deve ser adicionado ao modelo. Somente um objeto AStarNavigator faz-se necessário e permitido por modelo. Crie um objeto AStarNavigator ao clicar e arrastar da biblioteca para qualquer posição na superfície de simulação em 3D. Conectando os Membros Neste modelo, existe apenas um objeto executador de tarefa (TaskExecuter), no entanto, nós também queremos incluir o Rack como uma barreira. Faça um conexão com o 'A' entre o AStarNavigator e o operador. Isto pode ser feito mantendo a tecla A pressionada e clicando/arrastando do AStarNavigator para o operador, ou do operador para o AStarNavigator (não importando a ordem ou sequência de onde tem que partir a conexão). Um círculo em azul irá aparecer abaixo do operador. Faça uma conexão com o 'A' entre o AStarNavigator e o Rack. Um retângulo em azul irá aparecer abaixo do Rack. Adicione um Source e um Queue próximo ao operador conforme você pode visualizar em outra imagem mais abaixo. Criando Barreiras (Barriers) Junto com o Rack, vamos também criar um par de barreiras para representar paredes ou obstáculos que o operador não pode caminhar através. Clique no ícone do Divider na biblioteca para entrar no modo de criação. Clique em algum lugar ao lado direito do Queue (buffer) para criar um novo Divider. Clique duas vezes mais próximo dos pontos para mostrar a imagem abaixo para finalizar o Divider. Clique com o botão direito do mouse para sair do modo de criação. Adicione os Processors e um Sink conforme imagens abaixo. Faça a conexão deste o Source até o Sink usando a conexão com “A”. Clique sobre o ícone Barrier na biblioteca para entrar no modo de criação. Clique uma vez onde o canto esquerdo inferior do Barrier estará como mostrado abaixo. Clique novamente no canto direito superior para completar a configuração do Barrier. Clique com o botão direito para sair do modo de criação. Coloque o Barrier abaixo do Rack. Execute o Modelo Você pode agora resetar e executar o modelo para ver como será a performance do operador. Lembre-se, se você fizer qualquer mudança nas suas barreiras, o modelo obrigatoriamente deve ser resetado antes de ser executado novamente. Note que o operador encontrou o menor caminho para movimentar-se por cima e por fora do Divider. Embora exista diversas formas de alterar os caminhos do operador (por exemplo, estender ainda mais o tamanho do Divider), nós iremos modificar o caminho percorrido pelo operador, usando o Preferred Path. Crie Preferred Paths Preferred paths não são caminhos “configuráveis”, em vez disso, dará aos nodes associados com o caminho preferido, um peso maior no algoritmo de busca. Isso vai nos afetar, e puxar o operador para o caminho preferido. Clique sobre o ícone Preferred Path na biblioteca para entrar no modo de criação. Crie os dois seguintes Preferred Paths conforme mostrado na imagem abaixo. Preferred paths são unidirecionais e além do mais precisa ser posicionado no layout na ordem correta. Clique com o botão direito do mouse para sair do modo de criação. Execute o Modelo Resete e execute o modelo. Se o seu operador continuar a movimentar para cima e fora do Divider, você pode ou movimentar o Preferred Path ou alterar o Preferred Path weight na janela de propriedades do objeto AStarNavigator. Os Resultados do seu modelo podem variar deste exemplo conforme você posiciona suas barreiras e objetos, o que pode fazer a diferença no cálculo dos caminhos do operador. AStar Navigator Library O AStar é acessado na Biblioteca principal a esquerda: View Menu / Drag-Drop Library Existem 5 tipos de barreiras usada pelo A* Navigator. Estas barreiras modificam a grade usada no algoritmo de busca. Nota: Uma vez que as barreiras são criadas ou modificadas, o modelo precisa ser Resetado para recalcular o node table. Solid Barrier A mais simples das barreiras, a barreira sólida modifica a grade para remover uma área retangular, prevenindo os membros de viajar e (travel members) se movimentarem dentro da barreira. Divider Dividers desconectam os nodes ao longo de seu caminho, prevenindo os travel members de atravessarem o divider. Dividers podem ser modificados na superfície de simulação 3D ao arrastar o ponto final e intermediário. Qualquer número de pontos pode ser adicionado ao divider. One-Way Divider O One-way divider funciona de forma muito similar ao divider, no entanto, travel members são permitidos se movimentarem através do divider na direção das flechas em verde, neste caso, em direção ao topo da página. O one-way dividers pode ser modificado na superfície de simulação em 3D ao arrastar os pontos finais ou intermediários. Qualquer número de pontos podem ser adicionados em um one-way divider. Preferred Path Embora o preferred path não é uma barreira real, ele funciona da mesma forma que as barreiras fazem para modificar a tabela de nodes do A* Navigator. Em vez de modificar os nodes removendo os seus indicadores de direção, o caminho preferencial dá um peso maior a todos os nós associados com o percurso. Este valor de Path Weight pode ser alterado através da janela de propriedades do A * Navigator. O Path Weight tem de ser maior do que 0 e menor que 1, a fim de funcionar adequadamente. Valores acima ou abaixo deste podem causar resultados não intencionais. Os preferred paths podem ser modificados na visualização em 3D, arrastando os pontos do fim ou do meio. Preferred paths são unidirecionais. Qualquer número de pontos pode ser adicionado a um preferred path.
View full article
Neste Tutorial iremos demonstrar como importar um Layout do AutoCad no FlexSim. Desenhos do AutoCAD e outras imagens podem ser usadas como planta baixa para a montagem do modelo de simulação no FlexSim, sendo facilmente importadas usando o Background Drawing Wizard. Isto facilita a construção do modelo de simulação fazendo com que o modelador possa posicionar os objetos de forma rápida e em escala. O Background Drawing Wizard pode ser acessado clicando em: Tools / Visual / Model Background , ou na Biblioteca de Objetos / Visual / Background arrastando o objeto para o plano. O assistente abre uma nova janela, e irá pergunta-lo se você quer importar um desenho CAD ou um arquivo de imagem. Assegure-se que "AutoCAD Drawing" está selecionado e então clique em "Next". A próxima tela irá pedir a você que especifique o caminho do arquivo CAD que você quer usar; busque o arquivo em seu computador e clique em "Open". Veja que você está usando um arquivo .dwg; arquivos .dxf e .dwg podem ser importados para o FlexSim. Clique em "Next" novamente para ir para a próxima tela. Nesta tela você poderá definir detalhes sobre o posicionamento do seu layout no plano de trabalho do FlexSim. Existem três colunas representando os eixos X, Y e Z e três linhas para cada um que correspondem a posição, rotação e tamanho ao longo de cada eixo. Configure a posição para cada eixo em "0" e você verá a posição original do desenho, localizado no canto esquerdo inferior, mostrando exatamente que está no centro do seu modelo. Clique em "Next" para seguir para a próxima tela. Nesta tela você pode customizar qual layers de seu desenho CAD estarão visíveis, e ainda alterar a cor de cada layer. Se você tiver algum recurso no desenho que não é necessário para o modelo de simulação, como por exemplo, uma parede ou uma porta, talvez possa ser uma boa idéia fazer com que estes layers fiquem invisíveis e então o espaço visual não se torne confuso. Clique em "Next" para ir para a tela final. Clique em Finish e pronto! Agora você já pode começar a montar seu modelo utilizando o Layout em AutoCad como planta baixa.
View full article
O artigo "Using Fixed Resource Process Flows" que descreve algumas funções do Fixed Resource Process Flow tem um modelo de exemplo. O exemplo está em anexo e mostra como podemos utilizar do Fixed Resource Process Flow para multiplicar lógicas de fluxo e de trabalho. Esse representa uma área de despacho de produtos onde o produto vem de um estoque transportado pelo empacotador (Packer) e é preparado em uma paleteadora. Depois o produto é levado em lotes pelo empacotador para uma estação e dali ele vai ser despachado pelo carregador (Shipper). A função do Fixed Resource Process Flow facilita a replicação da lógica dessas paleteadoras e dos funcionários envolvidos. Alguns teste como se aumentássemos o número de recursos conseguiríamos suprir melhor a demanda podem ser realizados por esse recurso. Nesse artigo descreveremos o passo a passo desse modelo. A descrição segue no arquivo exemplo FR Flow em anexo.
View full article
Cams Module flexcon-cams v17.0.zip This module permits to place cameras in the model and so to follow an object using the nearest camera. How to install it: put the "Cams Module" folder into the Flexsim "modules" folder run Flexsim This module adds: the "Camera"object into the "Visual" section of the Flexsim standard library "Cams" menu button How to use it: insert cameras into your model where you want and adjust z locations (it's not important where camera is looking) highlight the object (maily a task executer) you want to follow click on the Cams menu voice: "Set Cam focus to highlighted" click on the Cams menu voice: "Camera activate" run the model the nearest camera to the focused object follows it click on the Cams menu voice: "Hide Cams and Camera Manager" to hide or unhide cameras Example:
View full article
In this phase You will be introduced to shared assets, specifically, zones. Post Office: Phase 3 Purpose Learn about Zone Shared Asset Description Restrict access to the waiting line queue so that only 5 Customers can be present at a time. Follow Up What happens to the 'Customers' that show up when the Zone is at capacity? How can we add Customer behavior that says if the waiting line is already full, they leave the post office? Video of Post Office: Phase 3 build: If you'd like to download the completed Post Office: Phase 3 model, you will find it here.
View full article
In this phase You will be introduced to Tasks, Tasksequences and Task Executors. In order to build Phase 2, you will need to start by having Post Office: Phase 1 pulled up in FlexSim. Tasks and Tasksequences Task A single instruction or action to be performed by a TaskExecuter object (ex. LOAD flowitem) Tasksequence A series of tasks to be performed in sequence. (example tasksequence with tasks below) Post Office: Phase 2 Purpose Modify our model to increase visual appeal. Description Create visuals so that the "Customer" flowitem looks and behaves more like a person standing in line, IE is able to walk to each location we send them to. Follow up How can the use of labels and resources help us easily add additional service desks? Video of Post Office: Phase 2 build: If you'd like to download the completed Post Office: Phase 2 model, you will find it here.
View full article
Building a Model In this training section we will introduce to you how to begin a modeling project. To begin, you need to gather all available information that describes the system, from how it looks to how it behaves. To build a model we take an incremental approach to the design and implementation of the model; think layers. We will be building a model in the following 5 steps: Create a 3D layout (this includes a CAD drawing, if available) Create a flowchart of the process steps Define the logic for each step, testing as you go Revise Logical steps as needed Run the model View results Post Office: Phase 1 Purpose Gain familiarity with Abstraction in models, Flowcharting steps, basic ProcessFlow activities Description Customers arrive at a post office every 45 seconds, on average. The statistical probability distribution which best simulates the inter-arrival pattern is an exponential distribution with a location value of 0 and a scale value of 45. The service time at the one and only service window in the post office is lognormal2(45,3.1,0.5) seconds. When the delay for service is complete, Customers leave the post office Follow Up (see video below at time 7:16) If there is more than one Token at the Delay activity, what does that say about how many Customers can be served at once? How can we apply limits to Tokens at activities? Video of Post Office: Phase 1: If you'd like to download the completed Post Office: Phase 1 model, you will find it here.
View full article
The FloWorks module has been updated for FlexSim 2017 and is now available (December 2016). Update 1: Bug fix update 1 was released on Jan 23, 2017. Update 2: Bug fix update 2 and FloWorks 17.1 for FlexSim 2017 Update 1 were released on Apr 11, 2017. FloWorks is a 3rd party module developed and maintained by Talumis BV ( talumis.com). It provides faster and more accurate modelling and calculation of fluid systems than the default FlexSim fluid library. It is especially useful within the oil, gas, and bulk industry both for production and supply chain optimization. This module requires a FloWorks license. For any questions, please email support@talumis.com. Release notes FloWorks version 2017.0.1 (Jan 23, 2017) Bug fix: Missing names and items in Flow Item Bin fixed. Bug fix: Properties window for Flow Tank flow item now opens correctly. Bug fix: Resolved some minor issues with "Add to dashboard" pins. FloWorks version 2017.0.0 (Dec 22, 2016) FloWorks updated for FlexSim 2017 Flow Mixer now has a manual mode, that will put it in Idle mode after each batch until you manually call StartMixerRecipe. Allow Input Rate and Output Rate to be plotted versus time. New Workability and Level Triggered Event objects added with focus in particular on modelling of ports and offshore processes. Unfilled part of Flow Tank is no longer necessarily gray but takes the object color. When Impact Events are active on a FloWorks object, they will show a box around the object similar to the "stopobject" behavior in standard FlexSim. The color of the box varies from red (0) through yellow to green (1) to black (infinity) depending on the impact factor of the event. Dropdown lists for port actions improved. For example, you can now open or close a single port (OpenFlowIp c.s.), select an individual port to open, close input and open output, etc. Increased limits on number of objects and events when running unlicensed version in FlexSim Educational version. Bug fix: Can now add Object Groups to FloWorks charts. Bug fix: When changing a Flow Task Executer from vessel to truck, the TE's flow tank is correctly scaled and positioned on reset. Bug fix: The State display in the Quick Properties did not correctly show the state of the Loading Arm. Bug fix: Arrow heads can now be dragged by holding 'X' key instead of Alt. User commands consolidated and documentation updated: ConnectFlowObjectToOtherObject command rewritten and documented. All documentation in modules\FloWorks\help\Commands reformatted and automatically generated based on actual user commands. These help pages often provide more explanation on the parameters and their optional values, the return types, and more extensive examples than the FlexSim Command Helper pages. Integration with the Process Flow module: FloWorks options added to "Listener Initialized" trigger of "Wait for event" action. Dropdown lists for port actions improved. For example, you can now open or close a single port (OpenFlowIp c.s.), select an individual port to open, close input and open output, etc. Backwards Compatibility Note: the following change may slightly change the way updated models behave. The Item To Flow's OnItemEmptied trigger is now fired before the actual item is destroyed, so that you are still able to reference it in the trigger code.
View full article
FlexSim 2017 is available. If you have bug reports please email dev@flexsim.com or post a new question to this answers site. If you have suggestions or new feature requests, create a new idea in the Development space. Release Notes Improved FlexScript performance by compiling and executing it as machine code instead of interpreted bytecode. Added new syntax to FlexScript for accessing objects' methods and properties, including dynamic label access. Improved OpenGL compatibility by removing many deprecated function calls and adding support for the OpenGL Core Profile. Added a mechanism for loading DWG data into the tree using the Model Background object. Added a new Snap to Background setting on the 3D view for snapping to points loaded from a DWG file. Upgraded the licensing system to Flexnet Publisher 2016 R1 (11.14). Changed the network licensing system so that you can open multiple FlexSim instances using only one license seat. Added a Quick Library popup to Dashboard views. Added Travel to Location pick option to OnResourceAvailable. Added Export Results to CSV pick option to the End of Experiment trigger Fixed some issues with auto-complete not displaying correctly. Fixed a crashing bug with settablesize() on tables with bundle data. Process Flow Added functionality for snapping activities into the middle of a block. Improved the Activities window, including renaming activities, better filtering options, and locating label references. Added a Billboard setting for Text objects. Added a right-click Edit Activity Visuals option. Added an option to the Create Object activity for positioning an object at another object's location without moving into that object. Added a Preserve Global Position checkbox to the Move Object activity. Updated the Schedule Source table so that it can add labels. Updated the Release Token activity to allow numbers and strings. Backwards Compatibility Note: the following changes may slightly change the way updated models behave. The new version of Flexnet Publisher requires network license servers to be upgraded. They need to use the latest vendor daemon and update the Flexnet Licensing Service. More information can be found in the license upgrade instructions at https://www.flexsim.com/ftp/LicenseServer/ Updated the Separator's order of events (executing OnEntry before Setup Time) to be consistent with the Processor. Users of the mesh api should update usage of GL_QUADS to use GL_TRIANGLES instead. GL_QUADS is deprecated and will not work when using the OpenGL Core Profile. Since the new FlexScript parser compiles to machine code, the order in which parameters are evaluated has changed to be aligned with the x86/x64 calling convention. This means models containing code where parameter evaluation order is important may have changed results. For example, the following code will have different results: myusercommand(duniform(1, 5), duniform(1, 10)) In the x86/x64 calling convention, parameters are evaluated from last to first. In this case, the duniform(1, 10) call will be called first. Since this call changes the state of random stream 0, changing the order of parameter evaluation changes the result. The new parser has a stricter grammar for the == and != comparison operators. The types of the operands must be the same or related. For example, the following code will now give compile errors because it is comparing unrelated types: double x = 0; treenode y = model(); if (x == y) { } This version introduces a new Array type, which is an array of variants, enabling a more feature rich array usage. In doing this, we are deprecating the old array types of doublearray, intarray, stringarray, and treenodearray. Specifically, the old array types are now just aliases for the standard Array type. This means that you can now, technically, put a string into a doublearray and vice versa, because they are all just Arrays. Hence we encourage you to just use Array in your code instead of the old array types. This change has also introduced a problem regarding the Variant type. In previous versions, the Variant could hold each of the four types of arrays, and it had a type value associated with each type, which you could get with the getvartype() command, comparing that value to one of VAR_TYPE_INTARRAY, VAR_TYPE_DOUBLEARRAY, VAR_TYPE_STRINGARRAY, or VAR_TYPE_TREENODEARRAY. Now, however, since we've merged all of those types into one, all of those values would theoretically be the same value, introducing issues if you had code that switches on getvartype(), or in some cases if you had a series of if/else compares on that value. Depending on the specific nature of that code, it would be hard to predict exactly how that code would behave going forward. Thus, we have decided to get rid of those old macros for each array type. Now there is just the macro VAR_TYPE_ARRAY. If you have existing code that uses the older macros, you will get compile errors when you open your model in version 17.0. We do this specifically so that you will be notified of code that needs to be updated. There are also several pick list options in the process flow module that use these older macros. Version 17 includes update scripts that will hopefully update all of those pick options in existing models to use the new VAR_TYPE_ARRAY macro instead of the old macros. With the new FlexScript parser, there are now some differences with how the parser compares a null variant to 0. In the old parser, the following expressions applied: (nullvar == 0) is false (nullvar <= 0) is true (nullvar >= 0) is true In the new parser, the following expressions apply: (nullvar == 0) is false (nullvar <= 0) is false (nullvar >= 0) is false This brings the <= and >= operators inline with the == operator. However, old code will evaluate differently now. The following expressions apply in both the new and old parsers: (nullvar < 1) is true (nullvar > -1) is true The param() command will now return nullvar if the parameter number is greater than the number of parameters passed to the function (previously it returned 0).
View full article
Every now and then, there are technical support questions that are asked more than once by different users. This article seeks to address a couple of “how to” questions that have come up over time. As such, this isn’t a massively technical paper just a quick look at a few things that might make your modeling experience more fun and your models a little more interesting. Background: This is a physical screening clinic similar in nature to those you might encounter either in the military or in a hospital that supports a large industrial area where employee physicals are required either by insurance companies or an employer. That said, it could even be a part of a much larger function like an ER. In a nutshell, patients that represent a mixed population of both men and women, are sent to the clinic without an appointment and arrive according to an exponential distribution. In the model, the mix of men and women is 50-50 although it can be altered to accommodate any distribution of patients. Once a patient registers, he/she is either directed to a gender-specific changing room where they change into a white surgical gown, or take a seat in the waiting room until a changing room is available. Once changed, each patient is escorted to an exam room by one of two nurse practitioners, is examined for a time period that is also gender-specific (men – normal(20,5,1), women – normal(17,3,1)), and is eventually released to return to a changing room and finally to leave the clinic. Any time there is no changing room available, patients take a seat in the waiting room. The clinic opens at 0800 hrs and closes at either 1600 hrs or after 1600 hrs when the last patient departs. Open and run the model, “changing-rooms-model-11-16-2016.fsm” to see the model in operation. Modeling challenges: The challenges are straight-forward and not at all complex. Specifically, they address the following questions: How do you stop patient arrivals (e.g. in-flow) at a certain time of day and then close the clinic when the last patient departs? How do you make sure that patients go to their own gender-specific changing rooms? How do you change a patient’s shirt color to white representing a patient gown and then back to their original color when they change back into their street clothes? How do you use a patient label to determine treatment time if a distribution is contained in the label? Flow Chart: Before we dissect the model, it’s probably not a bad idea to take a close look at the flowchart if only because, despite the model’s size, it can seem a little complex. Notice that the changing rooms really are the central point in the model. As such, connecting lines have to be constructed that link the Registration Area (0ne way), the waiting room (two way), the exam area (two way) and the Patient exit (one way) with each of the Changing rooms. Setting the Stage: Because the purpose of this model is to make provisions for and track both male and female activities, it uses two different PCIs (Patient classification Index numbers) to represent Men (PCI1) and Women (PCI2). Those PCIs and any related labels that may generally carry information about patients that might be used for decision making later, are initially entered in the Track Manager, under the tab labeled, "Patient Classification” as shown to the right. Note that, in this case, there are fields for identifying which Track a specific PCI will follow, what each PCI’s Acuity will be, which Gender different PCI’s will represent, which distributions represent each PCI’s Exam Time in the model, and a direct reference to which changing room a patient should use. Needless to say, each of the three types of fields – text, number and code – are accessible from various elements of the model and may be used to determine and isolate almost any patient characteristic a modeler might use to define patient Activities. One other “setting the stage” aspect of the model that deserves mention is the positioning of the nurses. Note that the two nurses aren’t arrayed in a single line, the default positioning of resources in a model, but rather are positioned as if they're having a conversation. Although somewhat inconsequential when a resource staff is small, large collections of staff members cry out for better, more life-like poses. To change a resource’s initial location in a model relative to its home base - in other words, it’s “Offset” – first make sure the model is in “3D View” by clicking on View>Model View (3D) in the main menu. Then, simply click on the individual resource and drag it to the place you’d like it to stand as its initial position. Note that the X Offset, Y Offset and Rot Offset values that are unique to each member of a resource group, will automatically be changed to the new coordinates. Finally, note that by clicking and holding down your left mouse button over any of the Offset positioning arrows (circled in red above), and then moving your mouse forward and back, you can also manually reposition any specific resource. Arrival Pattern : Open the Properties window for the Patient Arrivals Object to follow this discussion . The Patient Arrival pattern is simple to construct, involving nothing more than identifying the correct exponential distribution (i.e. exponential(0,20,1)) in the Patient Arrivals Properties’ Interarrival Time field as shown at the left. Notice also that the Patient Classification Index (PCI) field contains an expression to calculate and therefore generate two different PCIs. As mentioned previously, PCI 1’s are classified as men and PCI 2’s as women. In this case P(50.00, 1, 50.00, 2) insures that a mix of 50% men and 50% women will be generated by the Patient Arrivals Object during the model run. Setting Certain Patient and Model Characteristics : The purpose of the Patient Arrivals object isn’t only to create a unique pattern of patient arrivals but also to serve as the source of every patient’s initial characteristics as well as set certain actions that affect the performance of the model as a whole. In this case, changes to the patient’s appearance and the stopping time for patient arrivals are both determined in two different Patient Arrivals’ Property Triggers as shown at the right. Note that the “On Creation” Trigger is used to identify any actions the modeler might want to activate that occur when a patient is created for entry into the model. As shown, picklist option can be used in the On Creation Trigger to change any number of model parameters In this model, only that referring to the patient’s shirt color is changed. In this case, there are three entries to select from … (1) the fact that the patient’s shirt color should be changed, (2) which color palette should be used to obtain the desired color (Palette2), and (3) which color (by index number) should be used. Note that the color index number is determined by the patient’s PCI of either 1 or 2. Different palettes unique to the software can be viewed by selecting, “Edit > Color Palettes,” from the software’s main menu. Note that new palettes and/or colors may be added to the color palette editor by selecting the appropriate functional options (ie. Add/Delete Palette, More/Less colors). In this case, Male patients will wear green shirts and female patients will wear yellow. Note that the “OnExit” Trigger is used to identify any actions the modeler might want to occur when a patient exits the Patient Arrival object. In this case, the picklist option, “Stop or Resume Flow” is selected to act as a brake for patient arrivals after a specified elapsed time. Although there are seven different drop down options to select from regarding the condition desired to stop patients from entering the model, the option “time()>960” is selected to stop arrivals at 1600 hrs (4 p.m.). Note that “960” represents the elapsed time in minutes since midnight (time 00:00) of the first day of the model run. Many first time modelers make the mistake of assuming that the time value represents the elapsed time since the model’s beginning time, in this case 8 a.m., which isn’t the case. In any event, this picklist option examines the time of every patient’s departure from the Patient Arrivals object and the first patient created at or after 1600 hrs, automatically stops any additional patients from being created. Closing the Clinic’s Doors and stopping the model . Open the Properties window for the Patient Exit object to follow this discussion. Clearly there are two actions that are required to close the clinic at or after 4 p.m. when the last patient departs. The first is to close the front door which is accomplished by the “OnExit” Trigger found in the Patient Arrivals object as discussed in paragraph 5B above. The second is accomplished in the Patient Exit object’s “OnEntry” Trigger as shown at the right. In this case, the drop down picklist option, “Stop Model Based on Condition,” is selected and used to establish two criteria for the model’s end. The first criteria is that the elapsed time be later than 4 p.m. and the second is that there be no patients in the clinic when 4 p.m. arrives. The correct entry for the picklist option then, is shown at the left and takes both circumstances into account. What it determines every time a patient leaves the clinic is, what time it is and if anyone remains to complete treatment at that time. If the time is even a second past 4 p.m. and the clinic census is zero, the expression stops the model. So far, we’ve accomplished several tasks that include, (1) setting the patient’s shirt color, (2) establishing a criterion for closing the clinic door at 4 p.m. and stopping clinic operations at or after 4 p.m. when the last patient leaves, and (3) positioning resources at various places in the model rather than in a single straight line. Now, we need to change the patient’s shirt color to white – symbolizing changing into an examination gown – and back to its original color when the exam is over, and determine the patient’s Exam Time. It’s a simple process that we’ll cover in Activities 40, 60 and 80. Activity 10_Arrival: This activity causes the patient to walk unescorted from the Patient Arrival Object to the Registration Area. Although there’s nothing complex or unfamiliar about the activity, it’s important to note that even though this activity has no predecessors, a check mark is still required in the Predecessors box to cause the model to begin this activity without a command from some other activity. Activity 20_Registration : This activity causes the patient to use someone from the ClerkGroup at the Registration desk for normal(2,1,1) minutes to log in. Activity 30_TravelToChange1:This activity causes the patient to walk unescorted to one of the two changing rooms based on the patient’s sex. As such, which of the changing rooms is determined by the entry in the Patient Destination field, in this case, from the drop down picklist option, “Based on a Condition,” and by the edited drop down option, “getlabelnum(patient, "Gender") == 1 as shown to the right. Note that there are actually 12 different, “Choose a Condition” options the modeler can employ to set the patient’s destination. Activity 40_Change1 : This activity causes the patient to take normal(3,1,1) minutes to change into an examination gown and changes the patient’s shirt color from either green or yellow to white representing that change. The expression that causes the color change is contained in the Advanced Function, “Activity Finished Trigger.” In this case, the drop down picklist option, “Set Color” is selected to change a patient’s shirt to white as shown to the right. White is the color whose index number is 15 in the color palette 3. Activity 50_TvlToExam: This activity causes the patient to be escorted by a member of the NurseGroup from the changing room to the first available Exam room. Activity 60_Exam : This activity causes the patient to spend a period of time specified in the Processing Time field being examined by the same nurse that escorted them to the Exam room. Note that the exam time is entered by selecting the drop down picklist option, “Based on Patient’s Label,” and then by selecting the Patient Label, “ExamTime,“ that was previously set in the Patient Classification Index (PCI) Table. See Paragraph 3 above. Activity 70_TvlToChange2 : This activity causes the patient to walk unescorted to one of the two specifically named changing rooms. As such, which of the changing rooms is determined by the entry in the Patient Destination field, in this case, from the drop down picklist option, “Based on a Condition,” and by the edited drop down option, “getlabelnum(patient, "Gender") == 1 as shown to the right. See paragraph 7C for the same logic initially entering a changing room. Activity 80_Change2 : This activity causes the patient to take normal(3,1,1) minutes to change out of their examination gown and back into their street clothes by changing the patient’s shirt color from white back to their original color. The expression that causes the color change is contained in the Advanced Function, “Activity Finished Trigger.” In this case, the drop down picklist option, “Set Color” is again selected to change a patient’s shirt to its original color using the patient’s PCI number. Note that this is the same way the shirt color was assigned initially. See paragraph 5A Activity 90_Departure: This activity causes the patient to walk unescorted to the clinic exit and leave the model. Special Notes regarding the Changing Room model . As simple as the model may seem, it serves to reinforce several modeling techniques that we sometimes overlook. For example, … All activities are assigned unique Milestone names. In this case, TvlToChange1 and TvlToChange2 are identical in every respect. However, Change1 and Change 2 aren’t. To combine the four different activities into two identical activities would change the Patient Timeline widget in the Dashboard so that a patient’s time spent waiting for a nurse following the first Change would be combined as a single display element. This might make it difficult to glean specific information from the Timeline regarding total time changing and waiting for resources. The use of floor displays and walls to enhance a model’s appearance is highly encouraged. To design effective and realistic models, practice using the Infrastructure tools to create underlying floors and the Library tool, “Visual Objects,” to create enclosures.
View full article
In this example model you'll see two identical elevator setups. However, you will notice that ElevatorBank1 allows the patient to move to the next floor properly, whereas ElevatorBank1_2 will float the patient up the network node instead of using the elevator. There are a few steps you must follow to ensure you will have a properly working elevator in your model. Make sure everything is working the way you intended, without an elevator. Now you can add in the elevator, select it and then check the 'Connect to Path' box as seen below Now ensure that the elevator is connected to the nearest path node and any nodes above it. One thing to note is that after resetting if you click on any of the Path nodes that the elevator is connected to you will see that the On Arrival Trigger now says Send Message to Request Elevator. This is the code that actually calls the elevator when a patient arrives at the node. The elevator automatically adds this to the nodes connected to when resetting, but this trigger option can be added to any node. Another good practice, especially if patients walk by the elevator without always using it, is to make a separate node off on a spur. That way patients aren't triggering the elevator every time they walk by.
View full article
FlexSim 2017 Beta is available. (updated 30 Nov 2016) To get the beta, log in to your account at www.flexsim.com, then go to the Downloads section, and click on More Versions. It will be at the top of the list. If you have bug reports or other feedback on the software, please email dev@flexsim.com or create a new idea in the Development space. Release Notes Improved FlexScript performance by compiling and executing it as machine code instead of interpreted bytecode. Added new syntax to FlexScript for accessing objects' methods and properties, including dynamic label access. Improved OpenGL compatibility by removing many deprecated function calls and adding support for the OpenGL Core Profile. Added a mechanism for loading DWG data into the tree using the Model Background object. Added a new Snap to Background setting on the 3D view for snapping to points loaded from a DWG file. Upgraded the licensing system to Flexnet Publisher 2016 R1 (11.14). Changed the network licensing system so that you can open multiple FlexSim instances using only one license seat. Added a Quick Library popup to Dashboard views. Added Travel to Location pick option to OnResourceAvailable. Added Export Results to CSV pick option to the End of Experiment trigger Fixed some issues with auto-complete not displaying correctly. Fixed a crashing bug with settablesize() on tables with bundle data. Process Flow Added functionality for snapping activities into the middle of a block. Improved the Activities window, including renaming activities, better filtering options, and locating label references. Added a Billboard setting for Text objects. Added a right-click Edit Activity Visuals option. Added an option to the Create Object activity for positioning an object at another object's location without moving into that object. Added a Preserve Global Position checkbox to the Move Object activity. Updated the Schedule Source table so that it can add labels. Updated the Release Token activity to allow numbers and strings. Backwards Compatibility Note: the following changes may slightly change the way updated models behave. The new version of Flexnet Publisher requires network license servers to be upgraded. They need to use the latest vendor daemon and update the Flexnet Licensing Service. More information can be found in the license upgrade instructions at https://www.flexsim.com/ftp/LicenseServer/ Updated the Separator's order of events (executing OnEntry before Setup Time) to be consistent with the Processor. Users of the mesh api should update usage of GL_QUADS to use GL_TRIANGLES instead. GL_QUADS is deprecated and will not work when using the OpenGL Core Profile. Since the new FlexScript parser compiles to machine code, the order in which parameters are evaluated has changed to be aligned with the x86/x64 calling convention. This means models containing code where parameter evaluation order is important may have changed results. For example, the following code will have different results: myusercommand(duniform(1, 5), duniform(1, 10)) In the x86/x64 calling convention, parameters are evaluated from last to first. In this case, the duniform(1, 10) call will be called first. Since this call changes the state of random stream 0, changing the order of parameter evaluation changes the result. The new parser has a stricter grammar for the == and != comparison operators. The types of the operands must be the same or related. For example, the following code will now give compile errors because it is comparing unrelated types: double x = 0; treenode y = model(); if (x == y) { } This version introduces a new Array type, which is an array of variants, enabling a more feature rich array usage. In doing this, we are deprecating the old array types of doublearray, intarray, stringarray, and treenodearray. Specifically, the old array types are now just aliases for the standard Array type. This means that you can now, technically, put a string into a doublearray and vice versa, because they are all just Arrays. Hence we encourage you to just use Array in your code instead of the old array types. This change has also introduced a problem regarding the Variant type. In previous versions, the Variant could hold each of the four types of arrays, and it had a type value associated with each type, which you could get with the getvartype() command, comparing that value to one of VAR_TYPE_INTARRAY, VAR_TYPE_DOUBLEARRAY, VAR_TYPE_STRINGARRAY, or VAR_TYPE_TREENODEARRAY. Now, however, since we've merged all of those types into one, all of those values would theoretically be the same value, introducing issues if you had code that switches on getvartype(), or in some cases if you had a series of if/else compares on that value. Depending on the specific nature of that code, it would be hard to predict exactly how that code would behave going forward. Thus, we have decided to get rid of those old macros for each array type. Now there is just the macro VAR_TYPE_ARRAY. If you have existing code that uses the older macros, you will get compile errors when you open your model in version 17.0. We do this specifically so that you will be notified of code that needs to be updated. There are also several pick list options in the process flow module that use these older macros. Version 17 includes update scripts that will hopefully update all of those pick options in existing models to use the new VAR_TYPE_ARRAY macro instead of the old macros. With the new FlexScript parser, there are now some differences with how the parser compares a null variant to 0. In the old parser, the following expressions applied: (nullvar == 0) is false (nullvar <= 0) is true (nullvar >= 0) is true In the new parser, the following expressions apply: (nullvar == 0) is false (nullvar <= 0) is false (nullvar >= 0) is false This brings the <= and >= operators inline with the == operator. However, old code will evaluate differently now. The following expressions apply in both the new and old parsers: (nullvar < 1) is true (nullvar > -1) is true The param() command will now return nullvar if the parameter number is greater than the number of parameters passed to the function (previously it returned 0).
View full article
One of the most powerful commands in FlexSim is the query() command. It allows you to run SQL-like queries on virtually any data structure in the tree. If you don't know what that means, or what SQL is, or why it would be good to have SQL in FlexSim, this article is for you. If you have general ideas, but you would like to know more, then this article is for you. This article is not about connecting FlexSim to an external database. If that is your goal, then this article is not for you. Basics - Tables Data is often arranged in a table, which very loosely means that data is organized into rows and columns. However, SQL (and therefore the query() command) was designed to work only on certain kinds of tables, that look something like this: Name Age Fur Color Scooter 6 Brown Spot 3 Brown Whizby 4 Black Notice the following points about this table: Each column has a unique name There are no row headers (although if your table in FlexSim has data in the row header, that's okay; we'll get to that later) The table is a list of things, and each row in the table represents a single thing. The columns tell you the data that is stored about each thing. In this table, each thing is a pet, and each row stores the name, age, and hair color (the columns) of each pet. If our data included another pet, it would make another row in the table. In database lingo, a row in a table is called a record. One other thing you need to know about this table is that it has a name (in this case, "Pets"). All tables in SQL have a name, and follow the format described previously. Basics - Tables In FlexSim FlexSim has several different ways you can store data. Most users employ Global Tables and Lists (found in the toolbox) to manage data in their model. More advanced users sometimes create tables or bundles on labels. Then there's the model itself, which stores your object's locations in a tree data structure. All the data about where and object is, and how big it is, is stored in the model tree. So which of these data structures meet the standards for a SQL table? As far as the query() command is concerned, all of them do. The query() command is flexible enough to handle any data structure. The trick is to imagine your data as a table. To do this, you need to be able to answer the following questions: How many rows are there? What columns will the table have? How do you get the data for each cell? Phrased another way, given a row and a column, how do you put data in the table cell? If you can answer these questions, you can use the query() command. Let's apply these questions to two data structures in FlexSim: the Global Table, and the Global List. For the Global Table, the answers are very straightforward, but follow along to get the hang of it: Q: How many rows are there? A: The number of rows in the Global Table. Q: What columns with the table have? A: The same columns as in the Global Table. Q: How do you get the data for each cell? A: Given the row and column, look up the value in the Global Table For the Global List, things get a little more interesting: Q: How many rows are there? A: The number of entries on the list. Q: What columns with the table have? A: There is a value column, and there is a column for each field on the list. Q: How do you get the data for each cell? A: Remember that each row represents an entry on the list. For the value column, I get the value that was pushed on to the list to create the entry. For each field column, I get the value of the field for that entry. For example, suppose you have this list: Then supposed that you pushed a 5, 23, -12, 7, and 2 on to this list. When you view the entries on the list, you can see the data on this list laid out as a table: Notice that the value column has the values that were pushed on the list. The field columns (Doubled, Tripled, OddOrEven, and IsNegative) are each filled with the values of that field. The query() command has built-in support for Global Tables and Global Lists. However, it is always important to remember that to the query() command, the data is laid out in a table. If the data is not laid out in a table, you can still use the query() command, but you will need to use the methods explained in the Explicitly Defined Tables section. Basics - Queries SQL stands for Structured Query Language, so we can guess that it is a language for making queries. So what is a query? In a general sense, a query is a question. In SQL, a query is a question with two parts: who are you asking, and what do you want to know? There is a general answer to both parts of the question, and this is where tables come in. The answer to the first part (who are you asking?) is always a table. A SQL query is always directed at one (or more) tables. The answer to the second second part (what do you want to know?) is usually a new table. A SQL query takes in a table, and gives back a new table. The power in SQL comes from the new tables you can make. You can make a table that is a sorted version of the old table, like sorting data in excel. For example, if you have a list of items that need to be processed, you can sort that list by the item's priority. You can also make a table that is a filtered version of the old table, meaning you only kept certain rows. For example, if certain operators can only do certain tasks, you can make sure to only include the tasks that operator can do. In fact, you can make a table that is filtered, sorted, and modified in several other ways all with one query statement. Basics - Queries in FlexSim Let's look at examples of the query() command. You can follow along using the attached model ( numberlist.fsm). That model has a script that pushes values on to the list, and then queries the list. It also puts the result into the Global Table called QueryResult. Let's look at the line of that script with the query() command: int newTableRows = query("SELECT value FROM NumberList"); This line has a lot of new material. You can see that the query() command takes at least one argument, which is the text of a SQL query. We'll discuss the query itself in a moment. The query() command takes in the SQL query, and creates an internal (and invisible) temporary table that contains the result of the SQL query. It then returns the number of rows in the temporary table. Since you can't readily see the new table made by the query() command, you may want to copy the temporary table to a global table, using the dumpquery() command, as the script does: dumpquery(reftable("QueryResult"), 1); The temporary table lasts until you run the query() command again. Now for the query itself. You can see two parts of this query. The question "What do you want to know?" is answered by the SELECT statement. The question "Who are you asking?" is answered by the FROM clause. In this case, the FROM clause just lists one table, the NumberList. Recall that even though the NumberList isn't technically a table, you can visualize it's data as a table, which is what the query() command does (you can always right-click the NumberList in the Toolbox and choose the "View Entries" option to see the data as a table). In this example, the SELECT statement lists a column name. This means that the resulting table will have 1 column, because only one is required by the SELECT statement. When you run the script, it will put the result of the query in the QueryResult table: Notice that this table has only one column, the value column. If you look at the NumberList entries, you will see that this column is identical to the value column in that table. Examples To give you a general idea of what you can do with queries, these examples show a few common tasks. The examples all query the NumberList, which can be visualized as the following table: Selecting Multiple Columns SELECT value, IsNegative FROM NumberList Filtering SELECT value, IsNegative FROM NumberList WHERE IsNegative == 1 SELECT value, OddOrEven FROM NumberList WHERE value >= 5 Sorting SELECT value, Doubled FROM NumberList WHERE value >= 5 ORDER BY value Advanced - Callback Values It is often necessary to create a dynamic query. In FlexSim (not in regular SQL), you can do this by replacing a value in a query with a $n variable. This variable corresponds to additional parameters in the query() command. If you specify $1, then the value in the query will be the first additional parameter in the query() command, $2 will correspond to the second, and so on, up to $9. For example: query("SELECT Col1, Col2 FROM MyTable WHERE Col1 > $1 AND Col2 < $2", 10, 20) This query creates a table with Col1 and Col2, but only the rows where Col1 is greater than 10, and Col2 is less than 20. It is possible to include the values 10 and 20 in the query text. However, the $ variables allows you to easily change the value in the query, and replace them with more complicated expressions. Note that using callback values in a query where the FROM value is a Global List is not supported before versions 16.0.6/16.2.1. Advanced - Explicitly Defined Tables and the $iter() command Another FlexSim-specific feature of the query() command is the ability to explicitly define a table. This means you can query data that isn't arranged in the table format. In order to do so, you will need to answer the questions posed above, but shown again here: How many rows are there? What columns will the table have? How do you get the data for each cell? Once these questions are answered, the query() command can treat your data like a table. Each of the following subsections will answer these questions in detail. Defining the Number of Rows Let's start with a simple example: query("SELECT 1 FROM $1", 5) Notice that we are selecting from a number, not a Global Table or Global List. When the query() command sees a number instead of a table in the from statement, it assumes that you are querying a table with that number of rows. The statement above yields the following table (after a call to the dumpquery() command): This table has five rows, because $1 (the first additional parameter) evaluates to 5. All the rows have the value 1 because SELECT can handle expressions as well as column names (or expressions involving column names). Note that defining a table will only work if you use callback variables. A from statement like FROM 5 is not valid. To determine the number of rows in the table, use callback variables in the FROM statement. Defining the Columns To define the columns of your table, use the SELECT statement. Each expression in the SELECT statement will result in a column. When you are explicitly defining a table, you will often use callback variables as columns. This is where we can take advantage of the query() command. The query() command is very different from most other commands, because most commands only evaluate their parameters once. The query() command, however, can evaluate its parameters as many times as it needs to. Let's look at another example: query("SELECT $2 FROM $1", 5, normal(0, 1)) The result of this query is the following table: Notice that the second parameter, corresponding to $2, was re-evaluated as many times as the query needed it. Getting the Value in Each Cell Finally, we need a way to access the correct value for a given row and column. To do that, we need a way to know which row we are currently dealing with. This is where the $iter() command comes in. For example: query("SELECT $2 FROM $1", 5, $iter(1)) The $iter() command accepts an argument. That argument should match the value of the callback variable, e.g. if you used FROM $1, then the $iter() command should take a one as an argument. The $iter() command is linked to the query() command, so that its return value depends on which row is being evaluated. The above query results in the following table: Notice that $iter(1) returned the row number for each row. Now we can begin to query the tree, as if it were a table. Let's start with a simple example. Suppose you wanted a table of all the names of the first-level subnodes of the model tree. Let's start by answering the three questions: Q: How many rows are there? A: The number of first-level subnodes of the model Q: What columns with the table have? A: A column for the name of each of those subnodes Q: How do you get the data for each cell? A: Given the row number, get the name of that object Let's translate those answers into a query. First, we need to query something that isn't in table format already, so we know we need to use callback variables in the FROM statement: query("SELECT ... FROM $1", ..., ...) Next, we need a column for the names of all the subnodes, so we add one to the select statement: query("SELECT $2 FROM $1", ..., ...) Next, we need to answer the question of how many rows there are. Since this is the number of subnodes, you can write that as content(model()): query("SELECT $2 FROM $1", content(model()), ...) Finally, we need a way to get the name of each of the subnodes. We know that $iter(1) will give us the values from 1 to content(model()), so we can use those values in the rank() command, and we can pass the result of the rank() command to the getname() command: query("SELECT $2 FROM $1", content(model()), getname(rank(model(), $iter(1))) ) After dragging in a few random objects into the model, you can run that query. If you use the dumpquery() command, you can get a table like this: In the previous example, we used the value from $iter(1), and passed it in to rank(), and from rank() to getname(), all to get the name of the nth subnode of the model. Since querying a node in this way is fairly common, the query() command also allows you to specify a node as a table, rather than a number. In this case, $iter(1) will iterate over all the subnodes of $1, rather than the values 1 to $1. This makes our query much simpler: query("SELECT $2 FROM $1", model(), getname($iter(1))) Advanced - Flattening Data There is another option for what you can query in a FROM statement. If you use a callback variable (like $1) as your table, then you can use flattening syntax, shown in the following example: query("SELECT $3, $4 FROM $1x$2", 3, 2, $iter(1), $iter(2)) This query makes the following table: Notice that for every possible value of $1, there is a row for every possible value of $2. That is the purpose of the x (called the flattening operator); it ensures that there is a row for each permutation of all the callback variables involved. A query containing FROM $1x$2x$3x$4 would produce a table with enough rows for each unique combination of $iter(1), $iter(2), $iter(3), and $iter(4), and then execute the query on that table. The user manual contains an excellent example of when flattening syntax might be helpful, shown in the help manual in Miscellaneous Concepts > SQL Queries > Example.
View full article
One of the most powerful uses of a Fixed Resource Process Flow is to unify a set of machines and operators as a reusable entity. For example, many factories have several production lines. Simulation modelers often wonder what would happen if they could either open or close more production lines. If you were to open a new line, would the increased output be worth the cost? Or if you were to close a line, would the factory still be able to meet demand? These are the kinds of questions modelers often ask, and by using a Fixed Resource Process Flow, you can answer this question. This article demonstrates how to use a Fixed Resource Process Flow (or FR Flow) to coordinate several machines and operators as a single entity. The example model represents a staging area, where product is staged before being loaded on to a truck. However, most of the concepts that are discussed could be used in any Fixed Resource Process Flow. Creating a Collection of Objects When you set out to build a reusable FR Flow, it is usually best to start by making a single instance of the entity you want to replicate. Often, it is convenient to build that entity on a Plane. When you drag an object in to a Plane, it is owned by the Plane, which makes the Plane a natural collection. If you copy and then paste the Plane, the copy will have all the same objects as the original Plane. This makes it very easy to make another instance of your entity: just copy and paste the first. If the Plane is attached to an FR Flow, then the copy will also be attached to the same Flow, and will then behave the exact same way. In the example model, you will find a Plane with a processor, five queues, and two operators. This makes up a single staging area. The Plane itself is attached to the FR Flow, meaning an instance of the FR Flow will run for the Plane. It also means the Plane can be referenced by the value current . (You may find it helpful to set the reset position of any operators, especially if they wander off the plane at any point during the model run.) Using Process Flow Variables In order to drive the logic in your entity using an FR Flow, you will need to be able to reference the objects in each entity, so that they will be easily accessible by tokens. For example, if items are processed on Machine A, Machine B, and Machine C, in a production line, then you would want an easy way to reference those machines in each line. This is where Process Flow Variables come in. In the example model, you will find the following Process Flow Variables: Every staging area has a Packer, a Shipper, and a Palletizer, each referenced using the node command. Remember that current is the instance object, which is the Plane. Once these variables are in place, you could create an FR Flow like the following: If you ran this model with the Plane shown previously (complete with correctly named objects) and this flow with the shown variables, then the Packer operator would travel to the Palletizer. If you then copied the Plane, you would see that all Packers go to their respective Palletizers, as shown below: Using Variables and Resources Together Sometimes, you may want to adjust the number of operators per line, or even the number of operators in a specific role. To do this, you can again you Process Flow Variables. The sample model includes these variables: The sample model also includes these resources; the properties for the Shipper Resource are shown: Because this resource is Local, it is as if each attached object has its own version of this resource. Because it references a 3D operator, it will make copies of that operator when the model resets. The number of copies it creates will depend on the local value of the ShipperCount variable. To edit the value for a particular instance object, click on that object in the 3D view, and edit the value in the quick properties window. Disabling Entities Often, modelers simply want to "turn off" parts of their model. If that part of the model is controlled by a fixed resource flow, then you can easily accomplish this task. In the example model, you will find the following set of activities: The Areas resource is numeric, and it is global. The Limit Areas activity is configured so that any token that can't acquire the resource immediately goes to the Area Disabled sink. If the token that controls the process dies, then the area for that token is effectively disabled. The example model uses a Process Flow Variable to control how many areas can be active at a time: The Areas resource uses this value to control how many shipping areas are actually active. If this number is smaller than the number of attached objects, then some of the areas won't run. Note that the order the objects are attached in matters. The first attached area will be the first to generate a token in the Init Area source, and so will be the first one to acquire the area. Using Process Flow Variables in the Experimenter/Optimizer Currently, only Global and User Accessible variables can be accessed in the Experimenter. In the sample model, the only variable that can readily be used in an experiment is the TotalAreas variable, which dictates how many areas can be active. This allows the Experimenter or Optimizer to disable lines. To make it possible for the Experimenter or Optimizer to vary the number of Shippers or Packers per Area, the ShipperCount and PackerCount could be changed to Global Variables. You could put labels on the instance object (the Plane) that are read by the variable, like so: Then the experimenter could set the label value on the Plane object that is attached to the FR Flow. The Experimenter would set the label, which would affect the value of the Variable, which would affect how many copies of the Packer were created by the Packer resource. You could do the same for the ShipperCount variable. Sample Model The attached model (usingfixedresources-6.fsm) provides a working model that can demonstrate the principles in this article. It comes with only one Plane object attached to the FR Flow. Here are some things to try with the model: Reset and run the model to see how it behaves with a single area, where that single area has only one Packer and one Shipper. Create a copy (use copy/paste) of the Plane. Reset and run the model again to see how a second area is automatically driven by the same flow. You may need to adjust the TotalAreas variable if the second doesn't run. Adjust the number of Packers and Shippers (using the Process Flow Variables) on each Plane. Reset and run the model to see how adding more packers and shippers affects it. Create many copies of the first Plane (it is best to set the PackerCount and ShipperCount to 1 before copying). Reset and run the model, to observe the effect. Add or remove some staging areas (queues) to an Area. This model handles those changes as well (in the Put Stations On List part of the flow). Try to set up an experiment or optimization, that varies how many lines are active, and how many Packers and Shippers are in each. In general, play around with the sample model, or try this technique on your own. Other Applications This technique can be used to create production/packaging lines, complex machines, or any conglomerate of Fixed Resources and Task Executers. If you follow the methods outlined in this article, you will be able to create additional instances of complicated custom objects with ease. You will also be able to configure your model for use with the experimenter or optimizer.
View full article
[ FlexSim HC 5.1 ] FlexSim HC 5.1 is available. The start page will automatically notify you of the update and allow you to download and install the update from within FlexSim. To manually download the installer log in to your account at www.flexsim.com, then go to the Downloads section. If you have bug reports or other feedback on the software, please email dev@flexsim.com or create a new idea in the Development space. Missing DLL Error when Installing This version of HC requires certain files that should be present on windows if you're up to date on windows updates. If you're experiencing this error or another similar one please refer to this answer for more information. 5.1.0 Release Notes New Features Added a getremainingprocesstime() command. Areas can now be added as members to a shift schedule. Added support for code labels in Appointments table Added ability to resize code snippet windows. Added support for areas as well as locations in the Stop/Resume Flow pick list options. Improved the First Activity Satisfying All Its Requirements pickoption in the Next Activity field. Added pickoptions to easily diplay variables, labels, and table values on the screen. Column width and Row heights of the PCI table are now saved. Added a checkbox dashboard widget. Added more Data Collector pickoptions. Updated the ambulance and helicopter shapes. Added helicopter rotor animation. Added more chair and med station shapes. Added label columns to the Custom Arrivals table Bug Fixes Fixed Based on Simulation Time pickoption not working for weekly tables after the first week. Fixed a bug with undoing after deleting a network node. Fixed the resource utilization box plot when showing multiple periods. Fixed Experiment Variable drop down placement when the panel is scrolled. Fixed model resetting when Flowchart window was opened. Fixed the By Patient's location/area pickoption for the Process Time field so that quotation marks are no longer required. Fixed console errors being thrown by the Start Animation pickoption. Fixed console errors from the Patient's label pickoption for the Next Activity field. Fixed bug when a low priority OffSchedule event happens when a lower priority Lunch request is already queued up. Fixed Stop/Resume pick list error in User Event Trigger. Fixed a bug with reassigning task sequences when a resource goes off schedule and the resource's group is in an Alternate Group. Fixed refresh issues in the Sample Set Filter popup. Fixed a memory issue with the Entrance Criteria pickoption code. Fixed window positioning so they open centered on the application window. Fixed bug in "Based on Nurse Workload" pick list option for Patient Destination field. Fixed Output Raw Data not writing State headers. Improved positioning of ambulances and helicopters after a transport activity
View full article
Top Contributors