|
|
## Summary
|
|
|
|
|
|
- The goal of an output processor is to store data during the simulation.
|
|
|
- The base class of all output processors is `DataProcessor` which has a `doUpdate(SimulationState state)` method that is called in each simulation loop (see snippet below). By using the `simulationState`, an output processor can extract information about the current simulation state.
|
|
|
- All output processors are encapsulated within the `ProcessorManager` which is used by the main simulation loop to update all output processors.
|
|
|
|
|
|
```java
|
|
|
double currentTime = 0;
|
|
|
...
|
|
|
while (simIsRunning) {
|
|
|
...
|
|
|
model.update(currentTime);
|
|
|
...
|
|
|
SimulationState simulationState = new SimulationState(name, topography,
|
|
|
scenarioStore, simTimeInSec,
|
|
|
step, mainModel);
|
|
|
|
|
|
// The processor manager calls doUpdate() for each output processor.
|
|
|
processorManager.update(simulationState);
|
|
|
...
|
|
|
currentTime++;
|
|
|
}
|
|
|
```
|
|
|
|
|
|
## Output Processors and Output Files
|
|
|
|
|
|
Usually, an output processor is used to store data for all pedestrians in each simulation step (see snippet below). The data of all processors is written to file **after the simulation has finished**.
|
|
|
|
|
|
```java
|
|
|
@DataProcessorClass()
|
|
|
public class PedestrianPositionProcessor extends DataProcessor<TimestepPedestrianIdKey, VPoint> {
|
|
|
|
|
|
public PedestrianPositionProcessor() {
|
|
|
super("x", "y");
|
|
|
}
|
|
|
...
|
|
|
@Override
|
|
|
protected void doUpdate(final SimulationState state) {
|
|
|
Integer timeStep = state.getStep();
|
|
|
for (Pedestrian p : state.getTopography().getElements(Pedestrian.class)) {
|
|
|
this.putValue(new TimestepPedestrianIdKey(timeStep, p.getId()), p.getPosition());
|
|
|
}
|
|
|
}
|
|
|
...
|
|
|
}
|
|
|
```
|
|
|
|
|
|
In general, a single output processor generates a new column in the table-formatted output file. For instance, the `PedestrianPositionProcessor` generates the `x` and `y` column in the following output file:
|
|
|
|
|
|
```java
|
|
|
timeStep pedestrianId x y
|
|
|
1 1 1.0 1.0
|
|
|
1 2 2.0 1.0
|
|
|
2 1 1.5 1.0
|
|
|
2 2 2.1 1.0
|
|
|
...
|
|
|
```
|
|
|
|
|
|
Each data processor requires a row index to identify a row uniquely. The `key` must be given when implementing a specific output processor **public class PedestrianPositionProcessor extends DataProcessor**`<TimestepPedestrianIdKey, VPoint>`
|
|
|
|
|
|
## Steps to Implement a New Output Processor
|
|
|
|
|
|
1. Extend class `DataProcessor<RowIndex, ColumnValue>`, e.g. `PedestrianPositionProcessor extends DataProcessor<TimestepPedestrianIdKey, VPoint>`.
|
|
|
2. Implement `doUpdate()` method.
|
|
|
3. **Optional**: Define attributes for the output processor if the processor requires additional information, e.g. a measurement area. **Note:** The attributes of an output processor are automatically de-/serialized by Vadere in the GUI (see screenshot below). The attributes can be accessed within an output processor via the `getAttributes()` methods.
|
|
|
|
|
|
![VadereGUI-DataOutputTab](uploads/ac30df9a910f6c41327f7df02bd2c676/VadereGUI-DataOutputTab.png)
|
|
|
|
|
|
**Tip:** An output processor can use other output processors internally. For instance, a velocity processor could use a `PedestrianPositionProcessor` to store past pedestrian positions. Ensure in the `doUpdate()` method that the independent processor (the `PedestrianPositionProcessor`) is called before you access its data by using the `update()` method (**not** `doUpdate()`!). See following snippet:
|
|
|
|
|
|
```java
|
|
|
public class PedestrianVelocityProcessor extends APedestrianVelocityProcessor {
|
|
|
private PedestrianPositionProcessor pedestrianPositionProcessor;
|
|
|
...
|
|
|
@Override
|
|
|
public void doUpdate(final SimulationState state) {
|
|
|
pedestrianPositionProcessor.update(state);
|
|
|
|
|
|
// Now, pedestrianPositionProcessor.getValue(<rowIndex>) can be used to access data.
|
|
|
...
|
|
|
}
|
|
|
...
|
|
|
}
|
|
|
``` |
|
|
\ No newline at end of file |