The library includes blocks such as Tank, Pipeline, Valve, FluidSource, and FluidDispose. There are also blocks for routing, merging, and diverging the flow. In addition, there is an object FluidConveyor designed to model transfer of bulk or condensable matter. See the full list of Fluid Library blocks here.

The Fluid Library interoperates with the Process Modeling Library: it can convert agents into portions of fluid and vice versa.

The Fluid Library blocks put linear constrains on the flow rates, such as maximum rates, proportional rates, and so on. The library engine maximizes the flow throughout the system. As a result, the flow rates in the library are piecewise-constant (constant within time intervals), and only change instantly at discrete moments of time.

The linear nature of the flow dynamics allows for using LP (linear programming) solver to calculate the maximum rates. The solver is invoked only at the discrete moments of change, which makes the execution speed of the Fluid Library models a lot higher than that of the System Dynamics models. At the same time, the LP calculations are much more accurate as there is no notion of time step in the LP solver. We recommend using the Fluid Library when the system is linear, and using System Dynamics only for non-linear cases, i.e. when there are continuous feedback loops in the model, or continuous rate changes.

By default, these blocks of the Fluid Library ask the LP solver to maximize their outflow: FluidSource, AgentToFluid, Tank, and BulkConveyor. In addition, the FluidMerge and FluidSplit blocks in the priority mode will ask to maximize the flow at one of the inputs or outputs. Internally, this is done by raising the priority (coefficient) of the corresponding rate in the LP objective function. By default, the rate being maximized gets the priority 1, all other rates – 0. However, this will not always result in the desirable global picture. The user can create flowchart configurations with priority conflicts, and the library will not be able to figure out the correct global priorities without additional information. The Fluid Library allows you to provide that information in the form of custom priority values, see the corresponding parameters of the blocks listed above. The color indication of priority violation in FluidSplit and FluidMerge blocks may help you to track down issues with flow distribution.

If a rate evaluates to Utils.MAXIMUM_RATE (1.0E10) during runtime, the model stops with an error “Flow rate evaluated to the maximum value. You need to set a limit for this rate.” This is done because typically maximum rate is not normal and is a result of the user forgetting to set a limit somewhere. To avoid this, please set the upper limit for rate in flowchart block(s) where required.

In the Fluid Library, rates, amounts, time intervals, and other values are frequently recalculated with the use of linear formulas, e.g.: amount = rate * time interval, etc. As a result, numeric errors can occur. For example, if the tank capacity is
100 cubic meters, and the inflow keeps the rate of exactly 1 cubic meter per second for exactly 100 seconds, the "straightforward" implementation of the tank could result with the amount of, say, 100 /- 1e-12 cubic meters. The Fluid Library does its
best to minimize the effect of numeric errors by snapping the calculated values to where they should be. The snapping uses
Utils.TOLERANCE
– an internal constant that is applied across the library.

Here are some important places where
TOLERANCE
is used:

- Amounts of fluid in Tank, Pipeline, BulkConveyor, FluidSource, FluidToAgent, FluidPickup, and amount that flowed through Valve are snapped to 0 and, where applicable, to capacity.
- Tank, Pipeline, and BulkConveyor do not create batches of size less than TOLERANCE.
- Detection of Tank becoming full or empty, and detection of certain level being reached (above/below) is done with TOLERANCE.
- Obviously, all of the the above also applies to the composite blocks that contain Tank.
- FluidPickup and FluidToAgent detect accumulation of the given amount with TOLERANCE.
- In BulkConveyor density variations that are within TOLERANCE are not counted (do not result in new bulk "portions" being created).
- Amounts defined by the user cannot be less than
TOLERANCE, including: capacities, initial amounts, amounts to dispense or inject, portion size, etc.

Although normally you should not think about numeric errors while building models, sometimes the combination of time, rate, and amount units of different scale may cause very small numeric values, or small value variations, and then this knowledge may be useful.

Similarly, there is another notion of tolerance for rates, the corresponding constant is
Utils.RATE_TOLERANCE. Its value is 1.0e-9 and it works like this:

- If the user specifies a positive rate value that is lower than RATE_TOLERANCE, it is handled as an error.
- If during the rate recalculation a rate value evaluates to one lower than RATE_TOLERANCE, it is snapped to 0.

Theoretically, one can create a flow configuration that may cause a livelock (infinite event loop without progress in time). The simplest example would be a user action in the On rate change field of a Fluid Library block that causes another rate recalculation and, therefore, another call of On rate change. The recommendation, obviously, would be to avoid making such actions. However, more complicated situations may occur. For example, the event of a certain tank becoming empty can cause rate recalculation, which, in turn, can switch the tank to a non-empty state. This changes the rates back to the initial state, and the tank becomes empty again. Although there is no universal method to cure a livelock, a general advice would be to play with custom rate priorities in Split / Merge blocks in order to stabilize the rate system.