Monitored value
1. Overview
MonitoredValue
class is a class representing a value that changes at the specified rate as the simulation time goes and fires notifications when the value hits the specified thresholds.
This abstraction can be used to replicate any value that has rate and step changes and several values of interest that need to be notified about.
The rates at which the monitored value increases or decreases can be changed by calling setRate
method.
Current value can be instantly changed by calling setCurrentValue
method.
Thresholds are added by calling addThreshold
method.
Finally, handlers of threshold events are added by addAction
method.
Below is an example of usage of MonitoredValue
class:
Engine engine = new Engine();
// Create a new instance of a monitored value
MonitoredValue<String> monitoredValue = new MonitoredValue<>(engine);
// Set initial value
monitoredValue.setCurrentValue(10);
// Add a threshold - we will be monitoring the event of our variable becoming equal to 0
monitoredValue.addThreshold(0, "Value is zero");
// Our value will decrease with this rate
monitoredValue.setRate(-0.5);
// Add an action that will be executed.
// First argument of the handler is the value, second argument is the list of objects (in our case - strings) associated with the threshold
monitoredValue.addAction((x, s) -> System.out.println("Thresholds " + s + " are hit at model time of " + engine.time()));
// Start the engine and observe what is written to the console
engine.scheduleStop(100, "End of simulation");
engine.setFastMode(true);
engine.run(true);
2. Typical use case
To better understand the possible use cases of MonitoredValue
class let us consider a typical one.
2.1. The task
Consider we are modeling a vehicle which travels around, moves some cargo and consumes fuel. Let’s assume it has the fuel tank of 100 liters. And its fuel consumption rate depends on whether or not it is loaded and the grade of the road segments it’s currently moving on. Let us also assume we express the fuel consumption rate in liters per minute.
And now our task is to determine when are we going to need to go to a gas station for a refueling. To do this, we will be keeping track on how fast are we consuming the fuel which depends on where we are traveling and are we traveling loaded or empty. In the model logic, we want to be notified, for example, when there is just 10 liters remaining so that we can start moving to a gas station. And, of course, we also want to be notified when the tank is absolutely empty so that we can model the stoppage of our vehicle, which is a kind of an emergency situation. That is where this monitored value class might be of a great help for us.
2.2. The solution
The value will correspond to number of liters remaining in vehicle’s fuel tank.
An instance of MonitoredValue
will most probably be put inside the class of our vehicle agent.
We will use addThreshold
method to add two thresholds to this instance - one for 10 liters, and another one for 0 liters.
We will then use addAction
method to create handlers of our two events - hitting 10 liters level and running out of fuel.
Every time the vehicle enters a road segment, we will calculate and set the vehicle’s current fuel consumption rate by calling the setRate
method.
After refueling, we will tell that our tank is full again by calling the setCurrentValue
method with the argument of 100.
3. Objects associated with thresholds
MonitoredValue
class allows the developers to specify the type of objects associated with the thresholds.
In complex models this type can be an enumeration that contains the types of events that may happen when the value hits certain thresholds.
In our example above, there can be an enumeration like this:
enum FuelEvents { NEED_TO_REFUEL, EMPTY_TANK }
In simple models, however, we might be only interested in the value itself, thus String
or even Object
type can be used as type parameter.
Several objects can be associated with one threshold, that is why the second argument of a threshold event handler (added by addAction
method) is a list of objects, not a single object.
4. Getting the current state of monitored value
At any point of simulation time, a MonitoredValue
has current value and current rate at which the value is changing.
By default the rate is zero, it can be both positive and negative.
Current value can be retrieved by calling getCurrentValue
method.
Current rate can be retrieved by calling getCurrentRate
method.
5. Changing the current state of monitored value
MonitoredValue
class allows changing the value and its rate at any point in simulation time.
Moreover, both value and rate can be changed multiple times during the same simulation time.
In this case, all changes are applied in the same order as the corresponding methods are called.