Activity
An activity is a step in your process. Its capacity sets how much can happen at once, and its actions say what happens.
What it is
An activity is a process step: a shape on your diagram where entities wait and get worked on. It has a capacity, a queue on each side, and an ordered list of actions.
The question it helps answer
Where's the bottleneck, and what would relieve it? Activity results show how busy each step is and how long work queues in front of it, so you can see whether a step lacks capacity, is starved, or is blocked by the step after it.
How it behaves
- An entity arrives and joins the inbound queue, in arrival order unless Queue Ranking says otherwise.
- When the activity has a free unit of capacity, the entity takes it.
- The entity runs the actions in order, top to bottom. Processing time comes from these actions.
- Quodsi picks the outgoing connector. This happens after the actions, so routing can read any value they changed.
- The entity moves on when there's room at the next place. If there's no outgoing connector, it leaves the model.
If the next place is full, a finished entity stays put and keeps its capacity. That's blocking: the step looks busy, but it's waiting on the step after it. An outbound queue gives finished work somewhere to wait. By default, inbound and outbound queues are unlimited, so a line won't block until you set real buffer sizes.
A queue limit never turns work away. It holds back the step before it. Entities coming straight from a generator, or sent by a Split or Create action, keep waiting for a place even when the queue is full.
Breakdowns
With breakdowns on, each unit of capacity has its own cycle. It runs for a time drawn from MTBF (mean time between failures), fails, gets repaired for a time drawn from MTTR (mean time to repair), and the next cycle starts when the repair ends.
A failure takes a free unit if there is one. If every unit is busy, it interrupts one entity. That entity stays in the step, waits for the next unit to come free, then finishes its remaining time. Entities in the queue can't get ahead of it. On a step with several units, that can be before the repair ends, because any free unit will do.
An entity that has finished and is blocked is treated the same way. It can't leave until it has a unit back, even if room opens downstream in the meantime. Then it carries on waiting for the next place. Only a failure can take a unit from an entity: under Queue Ranking, a better-ranked arrival waits its turn.
Reading breakdowns in your results
A repair isn't work, and a unit under repair isn't capacity on offer. So Utilization and Share of time active leave repairs out. Being worked on, average still counts an entity sitting in a broken machine, because it's still there.
Time in failure adds up the repair time of every unit, so on a step with several units it can pass the length of the run. Failures counts the breakdowns, and Interruptions counts how many times a breakdown took a unit from an entity. Failure time for an entity type is only the repair those entities actually sat through. A breakdown on an empty unit belongs to no entity, so entity types won't add up to the step's Time in failure.
For example, take one entity with 20 minutes of work, on a step with an MTBF of 10 minutes and an MTTR of 5, over 100 minutes. The step fails 6 times, for 30 minutes. Two of those failures interrupt the entity, so it's in the step for 30 minutes: 20 working and 10 sitting out repairs. Utilization is 20 of the 70 minutes on offer, or 0.29. Share of time active is 0.20. Time in failure is 30, and the entity's failure time is 10.
Properties
Select an activity's shape to open its editor. The Basic, Actions, Financial, Routing and Levers tabs show in every complexity view. The Failure tab needs the Advanced view. Anything else that depends on a view says so below.
A view only changes what you can edit, never what runs. If an activity uses something your view hides, a line under the tabs names it, such as This uses failures, hidden in Basic, with a link to switch views.
Basic tab
| Property | What it does |
|---|---|
| Name | Names the activity in reports and on the diagram. An empty name or one another activity uses shows an inline message, and validation flags it. |
| Capacity: Fixed capacity | How many entities it can process at once, for the whole run. Default 1, and validation requires at least 1. |
| Capacity: Follow a schedule | Advanced view. Takes capacity from a work schedule instead. If the model has no schedule, Quodsi creates one with a Monday to Friday day shift at the current capacity, and opens it. If it has several, Quodsi links the first and tells you. |
| Work schedule | Shows while following a schedule. Picks which one. A link to a deleted schedule shows as Missing schedule, and validation reports it as an error. |
| Edit schedule | Opens the linked schedule. Other resources and activities following it change too. |
| New schedule | Creates a schedule, links it and opens it. |
| Nominal capacity (for reporting) | Shows while following a schedule. It doesn't change the run. It's what nominal utilization divides by, so use it to say what fully staffed means. Linking a schedule raises it to the schedule's highest capacity if it was lower. |
If an activity follows a schedule and you're not in the Advanced view, the option shows disabled, and the schedule still applies.
The rest of this tab is in the collapsed Advanced section. The section itself shows in every view.
| Property | What it does |
|---|---|
| Inbound Queue Capacity | How many entities can wait to enter. 999999 means unlimited, which is the default. 0 means no queue. |
| Outbound Queue Capacity | How many finished entities can wait to leave. 999999 means unlimited, which is the default. 0 means no queue, so a finished entity holds its capacity until it can move. |
| Queue Ranking: Serve by | Advanced view. Serves waiting entities by a value they carry, rather than first come, first served. It lists entity states of type number. If there are none, Create a "priority" state makes one. Every entity starts that state at 0, so ranking only takes effect once entities carry different values. Choose (first come, first served) to turn ranking off. |
| Queue Ranking: Order | Advanced view. Lowest value first (the default, where 1 is most urgent) or Highest value first. Available once Serve by is set. Ties keep arrival order. |
Actions tab
Actions are how an activity does its work. An entity runs them in order, one at a time. The tab has two views of the same list: Recipe, written as plain sentences, and Classic, as cards. Recipe is the default. The toggle at the top switches between them, and your choice is remembered in this browser.
- In Recipe, + Add step opens a list of steps grouped by purpose. Move a step with its arrows, and delete it with its ✕. Select a step to open its sentence, then edit the values in place.
- In Classic, + Add Action adds a Delay. Open a card to edit it, drag its handle to reorder, and delete it with its ✕.
Your view decides which actions you can add. An action already in the model stays, even if your view can't add that kind.
| Action (Classic) | In Recipe | Lowest view | What it does |
|---|---|---|---|
| Delay | Wait a while, or Use a resource | Basic | Takes time, with or without a resource. With a requirement, it gets the resource, waits Processing Time Duration, then gives it back. |
| Seize Resource | Grab a resource | Intermediate | Gets a resource and keeps holding it, so it can span several actions. The entity waits until the whole requirement is free. |
| Release Resource | Let a resource go | Intermediate | Gives back a seized resource. Leave the requirement as (release all) to give back everything the entity holds. |
| Assign State | Change a value | Intermediate | Changes state values. Takes no time. |
| Dispose Entity | Remove from model | Advanced | Removes the entity, even with connectors going out. It releases anything the entity holds, and any actions after this one don't run. |
| Split Entity | Split into copies | Advanced | Replaces the entity with Count new ones, and sends them to Destination Activity. The original is removed, so any actions after this one don't run. |
| Create Entity | Spawn a new entity | Advanced | Makes a new entity and sends it to Destination Activity. The original carries on. |
| Join Entities | Combine several | Advanced | Holds entities with the same Match State value until Join Count have arrived, then combines them into one and sends it to Destination Activity. The originals are removed. Each Join gathers its own entities, so two Joins in one activity never share them, even on the same Match State. |
| Loop | Repeat… | Advanced | Runs its Steps, in order, Repeat Count times. Steps can be any action, including another Loop. |
A model may also hold a Branch action, usually from an import. It keeps running, but you can't add one or edit its steps in the side panel.
Action properties
An entity waiting at a Join keeps its slot and anything it has seized until its batch completes. A failure while it waits doesn't change the batch. Entities still waiting when the run ends stay in this activity's contents. The new combined entity counts as a new entity, and the originals count as consumed, not completed.
The forms ask for a Join Count of at least 2 and a Repeat Count of at least 1. In a model written by hand or by an agent, a Join Count of 1 replaces each entity with a new one straight away, and a Repeat Count of 0 skips the Loop.
New entities from Split, Create and Join don't use connectors. They go straight to Destination Activity and join its queue. Each one copies Inherit States first, then applies State Modifications.
| Property | Action | What it does |
|---|---|---|
| Action Type | Every action (Classic) | Changes the kind of action. Other settings reset to defaults, keeping the name and any condition. Changing a Loop that has steps asks first, because its steps are removed. |
| Name | Every action (Classic) | Optional label, such as Triage. Step levers show it. |
| State Condition | Every action (Only if… in Recipe) | Intermediate view. Runs the action only if a test passes. If not, the entity skips it. Add state condition starts one: a State, a Comparison and a Value. Clear condition removes it. The test reads an entity state or a model state. See State. |
| Requirement | Delay | The resource requirement to use. (none — just a delay) means no resource. + New requirement… creates one, and the pencil edits the one selected. |
| Priority | Delay, Seize Resource | Advanced view. Shows once a requirement is chosen. 0 to 900, default 0. Higher wins when a resource is contested. Ties go to whoever has waited longest. |
| Keep resource after delay | Delay | Intermediate view. Shows once a requirement is chosen. Holds the resource after the delay rather than giving it back. Default off. |
| Processing Time Duration | Delay | How long it takes. A distribution and a Time Unit, drawn fresh on every visit. New actions use a constant 1 minute. In Recipe, type a value and unit, or use vary… to pick a distribution. See Randomness and replications. |
| Delay Duration | Older Delay | Some older models hold a Delay with only this field. It's the same as a Delay with no requirement. |
| State Modifications | Delay | Intermediate view. Changes states once the resource is held, before the time passes. Add modification opens a form with a State, an Operation and a value. See State. |
| State Modifications | Assign State | The changes to make, in order, with Add modification. In Recipe, use + change. |
| State Modifications | Split, Create, Join | Changes to make on the new entity. |
| Resource Requirement | Seize Resource | What to seize. Required: the model can't run until you pick one. |
| Resource Requirement | Release Resource | What to give back. (release all), the default, gives back everything. Otherwise pick the same requirement you seized. |
| Destination Activity | Split, Create, Join | Where new entities go. Required. It can't be this activity, so this activity isn't listed. |
| Count | Split | How many new entities. Whole number, default 1, minimum 1. |
| Entity Template | Split | The type for new entities. Use original's template is the default. |
| Entity Template | Create | The type for the new entity. Required. |
| Inherit States | Split, Create, Join | Tick the states to copy to the new entity. On Join they come from the first entity joined. |
| Split Index State | Split | Optional number state that gets each new entity's index: 0, 1, 2 and so on. |
| Match State | Join | The state to group by, such as an order number. Required. Use an entity state. |
| Join Count | Join | How many entities to wait for. Whole number, default 2, minimum 2. |
| Combined Template | Join | The combined entity's type. Use first entity's template is the default. |
| Join Count State | Join | Optional number state that gets the count joined. |
| Repeat Count | Loop | How many times to repeat. Whole number, default 1, minimum 1. |
| Steps | Loop | The actions to repeat. In Classic, use + Add step to loop. Conditions on the Steps are tested on every pass. |
Dispose Entity has no settings of its own.
Recipe keeps the sentence short. On Split, Create and Join, the optional settings are under More options: the new type, the index or count state, the states to copy, and Then set for State Modifications.
Some settings are only in Classic: Name, Keep resource after delay, editing Priority, and State Modifications on a Delay. Recipe shows a Priority above 0 in the sentence. A random draw or an expression in Change a value also shows in Recipe but opens through edit in Classic. That link and Edit in Classic show Classic for this activity only, without changing your choice of view.
Financial tab
The hourly rates are per hour whatever time unit your model uses, and each charges per unit of capacity. None of the costs can be negative. See Costing.
A unit is held from when an entity arrives in it until the entity leaves it, including time the entity spends waiting for a resource, waiting in a Join, blocked by the next step, or waiting out a repair. Only the time a Delay is running on it is billed at the working rate; the rest of a held unit's time is billed at the idle rate.
| Property | What it does |
|---|---|
| Enable financial tracking | Default off. While it's off the costs below are kept but hidden, and this activity costs nothing. |
| Fixed Cost | Charged once at the start of each replication, per unit of capacity. An activity following a schedule pays for the schedule's highest capacity. A warm-up doesn't remove it. Default 0. |
| Cost Per Entity Processed | Charged each time an entity starts at this activity, so an entity still here when the run ends is counted. Default 0. |
| Cost / Hour Active | Charged for each unit of capacity while a Delay is running on it. Two working units for an hour cost twice this. Default 0. |
| Cost / Hour Idle | Charged for each unit of capacity on shift with no Delay running on it. That includes a unit held by an entity waiting for a resource, for a Join match, to leave, or for a repair, and a unit under repair with nothing in it. An off-shift unit isn't idle, so it costs nothing. Default 0. |
A model saved earlier may show one more setting here, disabled and marked Not available yet. It has no effect on the run.
Failure tab
This tab needs the Advanced view. Below that, the tab is hidden and any breakdowns you've set still run.
| Property | What it does |
|---|---|
| Enable breakdowns (MTBF/MTTR) | Turns on random failures. Default off. While it's off the durations below are kept but hidden. |
| MTBF Duration | How long each unit runs from the end of one repair to its next failure, idle time included. A distribution and a Time Unit. Starts at a constant 60 minutes when you enable breakdowns. It can't be one that only ever gives zero: the unit would fail the moment it's repaired and never work, so validation refuses it. |
| MTTR Duration | How long a repair takes. A distribution and a Time Unit. Starts at a constant 5 minutes. Zero is allowed: the unit is back at once. |
A model saved earlier may show other settings here, disabled and marked Not available yet. They have no effect on the run.
Routing tab
This tab sets how entities choose between the activity's outgoing connectors. The tab shows one card per connector under Outgoing Connectors, named with its destination and its current share, rank or rule. Open a card to reach its move time. Connector explains each rule.
| Property | What it does |
|---|---|
| Connect Type | The routing rule. Default Probability, the only choice in the Basic view. State Condition, Entity Template and First Available arrive at Intermediate. A rule already set stays, shown disabled, in a lower view. Disabled with one or no outgoing connector, because there's nothing to choose. |
| Weight | Probability only. Relative share, with the resulting percentage beside it. Default 1. |
| State Condition | State Condition only. The test for this connector. |
| Entity Template | Entity Template only. The entity type this connector carries. |
| Priority | First Available only. Order of preference, lower goes first. Default 1. |
| Move time | Inside an open card. Travel time along the connector. |
Levers tab
Tick a setting to mark it as a lever, then give it a Label, a Sweep and a min, max and step. Settings are grouped under Capacity, Reliability and Cost.
| Property | What it does |
|---|---|
| Capacity | Marks capacity to vary. Hidden while the activity follows a schedule, because the schedule sets capacity. |
| Inbound queue capacity, Outbound queue capacity | The same, for each buffer size. |
| Step N — Processing time | One row for each Delay in the list, with the action's Name if it has one. Steps inside a Loop aren't listed. |
| Step N — Priority | Advanced view. One row for each Delay and Seize Resource in the list. It only matters on a step that uses a resource. |
| MTBF duration, MTTR duration | These show once breakdowns are on. |
| Fixed cost, Cost per entity processed, Cost / hour active, Cost / hour idle | These show once financial tracking is on. |
A lever you've already saved keeps its row, greyed with the reason, if its setting stops applying.
Example
An exam needs a nurse throughout and a doctor for part of it. Use Seize Resource for the nurse, then a Delay of 5 minutes for the intake. Add a Delay with a Doctor requirement for the exam itself, which gets and gives back the doctor. Finish with Release Resource for the nurse. The nurse is held across all of it, as in real life.
Common mistakes
- Leaving a seized resource held. A Seize, or a Delay with Keep resource after delay, holds until a Release, a Dispose, a Split or a Join, or until the entity leaves the model. Meanwhile other work queues for it, and it can follow the entity to later steps.
- Reusing a seized requirement on a Delay. If the entity already holds that requirement, the Delay doesn't get a second one. It then gives the requirement back when it ends, unless Keep resource after delay is on.
- Releasing a different requirement. A Release gives back what was seized under the requirement you pick. A different requirement for the same resource releases nothing. Pick the one you seized, or use (release all).
- A loop of steps that takes no time. If steps send entities round in a circle, or create entities at themselves, and none of them takes any time, the clock can't move. The run stops with a message naming a step. Give a step on the loop a duration, or a way out.
- Leaving Capacity at 1 on a Join. Entities wait for their match while holding capacity. With Capacity 1 and Join Count 2, the first entity fills the step and the second can't get in, so validation stops the model until Capacity is at least Join Count. Go higher if several groups can be open at once.
- Setting capacity when you mean a resource. Activity capacity is the limit of this step. If staff are shared between steps, model them as a resource.
- Expecting blocking with unlimited queues. Both queues default to unlimited, so upstream steps never block. Set real buffer sizes if blocking matters.
- Using a State Condition on an activity or resource state. Action conditions read entity states and model states, so the list offers only those. A condition saved on an activity or resource state stops validation until you choose one of them.
- Using Constant for human work. It hides the variability that creates your queues.