Commit ff341e0f authored by Stefan Schuhbaeck's avatar Stefan Schuhbaeck

rewrite pedestrianOverlapProcessor and add first step for SimulationResult object

parent 1e44a36c
package org.vadere.gui.projectview.view;
import org.vadere.simulator.projects.ProjectFinishedListener;
import org.vadere.simulator.projects.SimulationResult;
import org.vadere.simulator.projects.VadereProject;
import java.util.LinkedList;
import javax.swing.*;
public class ProjectRunResultDialog implements ProjectFinishedListener {
@Override
public void preProjectRun(VadereProject project) {
}
@Override
public void postProjectRun(VadereProject project) {
LinkedList<SimulationResult> simulationResultList = project.getSimulationResults();
String title = "Simulation Result: " + simulationResultList.getFirst().getScenarioName();
String infoMessage = "TotalOverlap: " + simulationResultList.getFirst().getTotalOverlaps();
// todo parentComponten to ProjectView?????
JOptionPane.showMessageDialog(null, infoMessage, title, JOptionPane.INFORMATION_MESSAGE);
}
}
......@@ -103,7 +103,7 @@ public class ProjectView extends JFrame implements ProjectFinishedListener, Sing
private ScenarioPanel scenarioJPanel;
private boolean scenariosRunning = false;
private Set<Action> projectSpecificActions = new HashSet<>(); // actions that should only be enabled, when a project is loaded
private ProjectRunResultDialog projectRunResultDialog = new ProjectRunResultDialog();
// ####################### Part of the control this should also be part of another class
// ##################
......@@ -225,6 +225,7 @@ public class ProjectView extends JFrame implements ProjectFinishedListener, Sing
model.getProject().addProjectFinishedListener(this);
model.getProject().addSingleScenarioFinishedListener(this);
model.getProject().addProjectFinishedListener(scenarioJPanel);
model.getProject().addProjectFinishedListener(projectRunResultDialog);
});
}
......
......@@ -29,7 +29,7 @@ public abstract class SourceController {
// Pedestrians should not touch each other in the spawn position.
// Therefore increase the spwan grid by 0.1.
public static final double SAFETY_OVERLAP_FACTOR = 1;
public static final double SAFETY_OVERLAP_FACTOR = 1.1;
protected final Source source;
private final DynamicElementFactory dynamicElementFactory;
......
......@@ -3,5 +3,5 @@ package org.vadere.simulator.projects;
public interface ProjectFinishedListener {
void preProjectRun(final VadereProject project);
void postProjectRun(final VadereProject scenario);
void postProjectRun(final VadereProject project);
}
......@@ -51,6 +51,8 @@ public class ScenarioRun implements Runnable {
private final RunnableFinishedListener finishedListener;
private SimulationResult simulationResult;
public ScenarioRun(final Scenario scenario, RunnableFinishedListener scenarioFinishedListener) {
this(scenario, IOUtils.OUTPUT_DIR, scenarioFinishedListener);
}
......@@ -66,6 +68,7 @@ public class ScenarioRun implements Runnable {
this.dataProcessingJsonManager = scenario.getDataProcessingJsonManager();
this.setOutputPaths(Paths.get(outputDir), overwriteTimestampSetting); // TODO [priority=high] [task=bugfix] [Error?] this is a relative path. If you start the application via eclipse this will be VadereParent/output
this.finishedListener = scenarioFinishedListener;
this.simulationResult = new SimulationResult(scenario.getName());
}
......@@ -79,6 +82,7 @@ public class ScenarioRun implements Runnable {
try {
//add Scenario Name to Log4j Mapped Diagnostic Context to filter log by ScenarioRun
// MDC.put("scenario.Name", outputPath.getFileName().toString());
simulationResult.startTime();
/**
* To make sure that no other Thread changes the scenarioStore object during the initialization of a scenario run
......@@ -98,6 +102,7 @@ public class ScenarioRun implements Runnable {
// prepare processors and simulation data writer
if(scenarioStore.getAttributesSimulation().isWriteSimulationData()) {
processorManager = dataProcessingJsonManager.createProcessorManager(mainModel);
processorManager.setSimulationResult(simulationResult);
}
// Only create output directory and write .scenario file if there is any output.
......@@ -116,6 +121,7 @@ public class ScenarioRun implements Runnable {
} catch (Exception e) {
throw new RuntimeException("Simulation failed.", e);
} finally {
simulationResult.stopTime();
doAfterSimulation();
//remove Log4j Mapped Diagnostic Context after ScenarioRun
// MDC.remove("scenario.Name");
......@@ -201,6 +207,10 @@ public class ScenarioRun implements Runnable {
return scenario;
}
public SimulationResult getSimulationResult() {
return simulationResult;
}
private void sealAllAttributes() {
scenarioStore.sealAllAttributes();
......
package org.vadere.simulator.projects;
import org.lwjgl.system.CallbackI;
import org.vadere.simulator.projects.dataprocessing.datakey.DataKey;
import java.time.Duration;
import java.time.Instant;
import java.util.Date;
public class SimulationResult {
private String scenarioName;
private Duration runTime;
private int totalOverlaps;
private String state;
private Instant startTime;
public SimulationResult(String scenarioName) {
this.scenarioName = scenarioName;
}
public void startTime(){
startTime = Instant.now();
}
public void stopTime(){
runTime = Duration.between(Instant.now(), startTime);
}
public String getScenarioName() {
return scenarioName;
}
public void setScenarioName(String scenarioName) {
this.scenarioName = scenarioName;
}
public Duration getRunTime() {
return runTime;
}
public String getRunTimeAsString(){
return runTime.toString();
}
public int getTotalOverlaps() {
return totalOverlaps;
}
public void setTotalOverlaps(int totalOverlaps) {
this.totalOverlaps = totalOverlaps;
}
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
}
......@@ -10,6 +10,7 @@ import java.nio.file.Paths;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Set;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
......@@ -29,6 +30,7 @@ public class VadereProject {
private Thread currentScenarioThread;
private ScenarioRun currentScenarioRun;
private PassiveCallback visualization;
private LinkedList<SimulationResult> simulationResults = new LinkedList<>();
private final ConcurrentMap<String, Scenario> scenarios = new ConcurrentHashMap<>();
private final BlockingQueue<ProjectFinishedListener> projectFinishedListener = new LinkedBlockingQueue<>();
private final BlockingQueue<SingleScenarioFinishedListener> singleScenarioFinishedListener =
......@@ -214,6 +216,11 @@ public class VadereProject {
// Getter...
public LinkedList<SimulationResult> getSimulationResults() {
return simulationResults;
}
public BlockingQueue<Scenario> getScenarios() {
return scenarios.values().stream().sorted((f1, f2) -> f1.getName().compareTo(f2.getName())).collect(Collectors.toCollection(LinkedBlockingQueue::new));
}
......@@ -272,6 +279,7 @@ public class VadereProject {
notifyScenarioRMListenerAboutPostRun(getCurrentScenario());
projectOutput.update();
simulationResults.add(currentScenarioRun.getSimulationResult());
if (scenariosLeft.isEmpty()) {
for (ProjectFinishedListener listener : projectFinishedListener) {
......
......@@ -2,6 +2,7 @@ package org.vadere.simulator.projects.dataprocessing;
import org.vadere.simulator.control.SimulationState;
import org.vadere.simulator.models.MainModel;
import org.vadere.simulator.projects.SimulationResult;
import org.vadere.simulator.projects.dataprocessing.outputfile.OutputFile;
import org.vadere.simulator.projects.dataprocessing.processor.DataProcessor;
......@@ -21,6 +22,7 @@ public class ProcessorManager {
private Map<Integer, DataProcessor<?, ?>> processorMap;
private List<OutputFile<?>> outputFiles;
private SimulationResult simulationResult;
public ProcessorManager(List<DataProcessor<?, ?>> dataProcessors, List<OutputFile<?>> outputFiles, MainModel mainModel) {
this.mainModel = mainModel;
......@@ -60,6 +62,7 @@ public class ProcessorManager {
public void postLoop(final SimulationState state) {
this.processorMap.values().forEach(proc -> proc.postLoop(state));
this.processorMap.values().forEach(proc -> proc.postLoopAddResultInfo(state, simulationResult));
}
public void setOutputPath(String directory) {
......@@ -70,6 +73,9 @@ public class ProcessorManager {
this.outputFiles.forEach(file -> file.write());
}
public void setSimulationResult(SimulationResult simulationResult) {
this.simulationResult = simulationResult;
}
/**
* Returns true if there is no output to write, otherwise false.
......
......@@ -35,7 +35,7 @@ public class TimestepPedestrianIdOverlap implements DataKey<TimestepPedestrianId
}
public String[] toStrings(){
return new String[]{Integer.toString(timeStep), Integer.toString(pedId1), Integer.toString(pedId1)};
return new String[]{Integer.toString(timeStep), Integer.toString(pedId1), Integer.toString(pedId2)};
}
@Override
......
package org.vadere.simulator.projects.dataprocessing.processor;
import org.vadere.simulator.control.SimulationState;
import org.vadere.simulator.projects.SimulationResult;
import org.vadere.simulator.projects.dataprocessing.ProcessorManager;
import org.vadere.simulator.projects.dataprocessing.datakey.DataKey;
import org.vadere.state.attributes.processor.AttributesProcessor;
......@@ -115,6 +116,10 @@ public abstract class DataProcessor<K extends DataKey<K>, V> {
public void postLoop(final SimulationState state) { }
public void postLoopAddResultInfo(final SimulationState state, SimulationResult result){
}
public void init(final ProcessorManager manager){
this.data.clear();
this.lastStep = 0;
......
......@@ -2,22 +2,11 @@ package org.vadere.simulator.projects.dataprocessing.processor;
import org.vadere.annotation.factories.dataprocessors.DataProcessorClass;
import org.vadere.simulator.control.SimulationState;
import org.vadere.simulator.projects.SimulationResult;
import org.vadere.simulator.projects.dataprocessing.ProcessorManager;
import org.vadere.simulator.projects.dataprocessing.datakey.NoDataKey;
import org.vadere.simulator.projects.dataprocessing.datakey.TimestepPedestrianIdKey;
import org.vadere.state.attributes.processor.AttributesEvacuationTimeProcessor;
import org.vadere.state.attributes.processor.AttributesNumberOverlapsProcessor;
import org.vadere.state.attributes.processor.AttributesPedestrianOverlapProcessor;
import org.vadere.state.attributes.processor.AttributesProcessor;
import org.vadere.state.scenario.Pedestrian;
import org.vadere.util.geometry.shapes.VPoint;
import javax.swing.JOptionPane;
import javax.print.attribute.IntegerSyntax;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
/**
* This processor counts the number of overlaps during a simulation run.
......@@ -47,29 +36,14 @@ public class NumberOverlapsProcessor extends DataProcessor<NoDataKey, Long> {
public void postLoop(final SimulationState state) {
this.pedOverlapProc.postLoop(state);
long numberOverlaps = this.pedOverlapProc.getValues().stream().mapToInt(val -> val.intValue()).sum() / 2;
/* // Uncomment this code if you want to get the info box with the number of overlaps
if (numberOverlaps > 0 ) {
NumberOverlapsProcessor.infoBox(numberOverlaps + " Overlaps have occured during the simulation!", "Number Overlaps");
System.out.println("* CAREFUL *: " + numberOverlaps + " Overlaps have occured during the simulation!");
}else{
NumberOverlapsProcessor.infoBox("No Overlaps have occured during the simulation :)", "Number Overlaps");
}
*/
long numberOverlaps = this.pedOverlapProc.getData().size()/2;
this.putValue(NoDataKey.key(), numberOverlaps);
}
/*
// Uncomment this code if you want to get the info box with the number of overlaps (if > 0)
public static void infoBox(String infoMessage, String titleBar)
{
JOptionPane.showMessageDialog(null, infoMessage, titleBar, JOptionPane.INFORMATION_MESSAGE);
}*/
@Override
public void postLoopAddResultInfo(final SimulationState state, SimulationResult result){
result.setTotalOverlaps(this.pedOverlapProc.getData().size()/2);
}
@Override
public void init(final ProcessorManager manager) {
......
......@@ -3,20 +3,26 @@ package org.vadere.simulator.projects.dataprocessing.processor;
import org.vadere.annotation.factories.dataprocessors.DataProcessorClass;
import org.vadere.simulator.control.SimulationState;
import org.vadere.simulator.projects.dataprocessing.ProcessorManager;
import org.vadere.simulator.projects.dataprocessing.datakey.TimestepPedestrianIdKey;
import org.vadere.simulator.projects.dataprocessing.datakey.TimestepPedestrianIdOverlap;
import org.vadere.state.attributes.processor.AttributesPedestrianOverlapProcessor;
import org.vadere.state.attributes.processor.AttributesProcessor;
import org.vadere.state.scenario.DynamicElement;
import org.vadere.state.scenario.Pedestrian;
import org.vadere.state.scenario.Topography;
import org.vadere.util.geometry.LinkedCellsGrid;
import org.vadere.util.geometry.shapes.VPoint;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;
/**
* @author Mario Teixeira Parente
*/
@DataProcessorClass()
public class PedestrianOverlapProcessor extends DataProcessor<TimestepPedestrianIdKey, Integer> {
public class PedestrianOverlapProcessor extends DataProcessor<TimestepPedestrianIdOverlap, Double> {
private double pedRadius;
private double minDist;
public PedestrianOverlapProcessor() {
......@@ -28,9 +34,22 @@ public class PedestrianOverlapProcessor extends DataProcessor<TimestepPedestrian
protected void doUpdate(final SimulationState state) {
this.pedRadius = state.getTopography().getAttributesPedestrian().getRadius(); // in init there is no access to the state
Collection<Pedestrian> peds = state.getTopography().getElements(Pedestrian.class);
peds.forEach(p -> this.putValue(
new TimestepPedestrianIdKey(state.getStep(), p.getId()),
this.calculateOverlaps(peds, p.getPosition())));
minDist = pedRadius * 2;
int timeStep = state.getStep();
for (Pedestrian ped : peds) {
// get all Pedestrians with at moust pedRadius*2.5 distance away
// this reduces the amount auf overlap test.
VPoint pedPos = ped.getPosition();
List<DynamicElement> neighbours = getDynElementsAtPosition(state.getTopography(), ped.getPosition(), pedRadius*2.5);
// collect pedIds and distance of all overlaps for the current ped in the current timestep
List<Pair> overlaps = neighbours
.parallelStream()
.map(p -> new Pair(p.getId(), p.getPosition().distance(pedPos)))
.filter(p -> ped.getId() != p.id)
.filter(Pair::isOverlap)
.collect(Collectors.toList());
overlaps.forEach(o -> this.putValue(new TimestepPedestrianIdOverlap(timeStep, ped.getId(), o.id), o.dist));
}
}
@Override
......@@ -41,8 +60,9 @@ public class PedestrianOverlapProcessor extends DataProcessor<TimestepPedestrian
this.pedRadius = att.getPedRadius();
}
private int calculateOverlaps(final Collection<Pedestrian> peds, VPoint pos) {
return (int) peds.stream().filter(p -> p.getPosition().distance(pos) <= 2 * this.pedRadius).count() - 1;
private List<DynamicElement> getDynElementsAtPosition(final Topography topography, VPoint sourcePosition, double radius) {
LinkedCellsGrid<DynamicElement> dynElements = topography.getSpatialMap(DynamicElement.class);
return dynElements.getObjects(sourcePosition, radius);
}
@Override
......@@ -53,4 +73,19 @@ public class PedestrianOverlapProcessor extends DataProcessor<TimestepPedestrian
return super.getAttributes();
}
class Pair{
int id;
double dist;
public Pair(int id, double dist) {
this.id = id;
this.dist = dist;
}
boolean isOverlap(){
return dist < minDist;
}
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment