Well-structured models that don’t crumble: a workshop in AnyLogic modeling

Jenga on a dark gray background

Imagine you’ve been working on a complex model for months, and just when it is almost ready, a client asks you to make a substantial change to it. Days of additional work ahead, restructuring, and trying to fit in something that was not initially meant to be there. Sounds daunting, doesn’t it?

Is there a way to avoid situations like this or at least make them less painful? The answer lies in a solid model foundation that leaves room for flexibility and gives you full control over your simulation.

How to structure a simulation model so that it doesn’t crumble when sudden changes need to be implemented was the focus of a workshop from Dr. Benjamin Schumann, a simulation expert with over a dozen years of experience. Given at AnyLogic’s global conference and now shared online, the workshop is a detailed guide for all skill levels on how to build robust models.

This blog post is an overview of the latest How to Structure Your Models So They Never Crumble workshop which uses an example of a factory model to dive deeper into technical details for beginners, advanced, and super advanced AnyLogic users.


The basics: visual structure and embedded agents

Those who just start working with AnyLogic tend to build models by simply dragging and dropping elements on the canvas. It’s easy and quick and could be suitable for small projects. However, with large and complex models, Ben suggests taking a safer, though longer, path of laying a solid foundation first.

Instead of piling up model elements on the canvas, you could group them in colorful rectangles like the ones below for each agent. You can also define what each agent type is supposed to do above those rectangles. For example, your Main agent could only hold the actual model and handle data.

Four colorfuls rectangles with model elements written on them
Grouping model elements

What most AnyLogic users would do next is build the model logic directly in the Main agent. Ben’s suggestion, though, is that you put it in a separate agent called Model, which will then be embedded in Main. All this brings transparency and flexibility later in the project.

For an even higher degree of flexibility and control over agents, you should always create an initially empty population of agents instead of a single agent type.

Window for creating a model population in AnyLogic
Creation of a model population in AnyLogic

In the workshop’s factory simulation example, there are two acting agents – products and machines. For each of them, Ben creates a separate agent within Model. Another suggestion here is that you draw a simple hierarchy scheme in Main using agent statecharts. Doing so will help you keep track of the relations between agents in your model.

A statechart representing the model's hierarchy in AnyLogic
A statechart representing the model's hierarchy

Model sanity check and more agent hierarchy tricks wrap up this section in the video.

Advancing your skills: generic flow charts and object-oriented programming concepts

As users tend to put the model logic in Main, it could get messy in large and complex projects and therefore become error-prone. One way to simplify your process modeling flowcharts could be to create a custom flowchart block for repetitive block sequences. Another solution is to split up the flowchart so that different parts of it sit in respective agents. Let's examine the second one in more detail.

Circling back to the example of a factory simulation, let’s say the machine agent (A_Machine) and product agent (A_Product) have their own flowchart. Products visit machines one by one, and each product has a to-do list of machines it must visit.

To set this process in motion, Ben first creates a function that lets him control the order in which machines or products are created on model run. Secondly, he sets parameters that specify the agents. The way he does that for each agent individually, by following the Encapsulation principle of object-oriented programming, will help him in the future – if the circumstances call for a change in the model, he won’t need to massively rewrite the code.

If each agent has its own flowchart, how does this all work as a system?

A product arrives at the factory and goes to the first machine to be processed:

A flowchart for product processing – in AnyLogic
A flowchart for the product in Main

Then it is processed for some time and either moves to the next machine or leaves the factory:

A flowchart of how the machine processes the product – in AnyLogic
A flowchart of how the machine processes the product – in Machine agent

When the machine finishes processing the product and sets it to leave the factory, it sends the product to the Sink block in Main.

A flowchart of how the product leaves the factory after being processed – in AnyLogic
A flowchart describing that the product has been processed and leaves the factory

Advancing your skills: generic KPIs and animation

One of the key principles of good modeling is to separate logic from visualization. Following this principle, Ben suggests creating separate agents that will spy on their corresponding agents (in our example, those are A_Machine and A_Product) and tell you how they are performing in the form of charts. This also serves to give you full control over generic KPIs, avoid mistakes in measuring agent activities, and make your logic agent computation more efficient.

You can do it with a pinch of Java magic, the creation of spying agents, and setting their parameters and functions. Finally, you’ll need to use more Java code to make Main understand how to display the KPIs for machines.

A model statechart representing an updated hierarchy
Updated model hierarchy with the UI_Machine agent

Regarding animation, a simple rule could be applied: if a model has objects that are supposed to be moving, then set the animation in the logic agent directly. Otherwise, set it in spying agents.

Taking it a step further: dashboards and data handling

Now that you have different spying agents that display statistics, why don’t you group them together in a new agent called Dashboard so that you have the flexibility to create whatever dashboards you want? For example, you could choose to show only charts for machines and the exact place where to put actual animation for them on the dashboard.

If you’d like to add more agent types, let’s say products, to the dashboard, all you need to do is create another parameter, a population of agents (pop_UI_Product), and a function that would create products. Then position the dashboards in the way you want them to be seen.

The Dashboard agent itself should be embedded in Main, and you should create a function that launches the animation.

A model statechart representing an updated hierarchy
Updated model hierarchy with the UI_Dashboard agent

Wrapping up the workshop, Ben shares his tips on loading and storing model data. While the common principle of good modeling is to separate data from the model, his suggestion is that you take it a step further and put an additional layer in between – Model inputs. Why does he find this approach powerful?

Real data could be messy and change over time, and a model needs nicely formatted and clean data to keep running. What the Model input layer does here is translate the data to the model, so that it always has processed inputs to work with. This setup also has another application – testing.

So if the real data structure changes, you would only need to make slight changes to this Model input layer, and the model would still work. It wouldn’t feel the impact.

For this to work, first, you need to add data to an Excel spreadsheet. Then you create a Java class called POJO (plain old Java object) for each data structure (for example, for machines) and duplicate the structure using Java code.

Data structure in Excel
Data structure in Excel
Data structure in Java code
Data structure duplicated in Java code

The next step is to create a Java class called InputData that will, on the one hand, load the data from the Excel file and, on the other hand, create new data for testing.

Java code for InputData in AnyLogic
Code for InputData that creates an instance that loads data from a given Excel file and another instance with pre-created data

Now you can define your model by the input data (use a parameter for that) in Model agent. So, when you need to add more characteristics to, for instance, your factory machines, you won’t have to create dozens of new parameters for that.

In Main, you would need to set the agent’s actions right. When you start the model, Main should be able to first load the data, then create the model and its agents, and finally launch the animation, which is an optional step.

Key takeaways and the workshop video

The tricks and approaches in this workshop might not look quick and easy to implement, but they provide you with flexibility and full control over your model, which becomes vital in large and complex projects.

To recap, here are four key takeaways from this workshop:

  1. If you’re a beginner, use Model as an agent embedded in Main.
  2. If you’re a bit more advanced, start to encapsulate your agents and functions. Keep in mind that an agent is specified via parameters, and a function is specified via arguments.
  3. Separate animation from your model’s logic. Create spy agents that would track other agents’ performance. There’s no need for Dynamic animation properties, you have your spy agents, and you just need to update them from time to time.
  4. Don’t just separate real data from your model but have a Model input layer in between. This approach makes you independent from your client’s data and makes your model more robust.

Watch the How to Structure Your Models So They Never Crumble workshop and take a deep dive into better simulation modeling practices.

Subscribe to our monthly newsletter so we bring our latest blog posts directly to your inbox.

Related posts