11.08., 9:00 - 11:00: Due to updates GitLab will be unavailable for some minutes between 09:00 and 11:00.

Commit 16081320 authored by Stefan Schuhbaeck's avatar Stefan Schuhbaeck

add new version 0.6 to cleanup overlap processor

parent 46915268
This diff is collapsed.
This diff is collapsed.
......@@ -18,7 +18,8 @@ public enum Version {
V0_2("0.2"),
V0_3("0.3"),
V0_4("0.4"),
V0_5("0.5");
V0_5("0.5"),
V0_6("0.6");
private String label;
......
......@@ -10,6 +10,7 @@ public class SimulationResult {
private String scenarioName;
private Duration runTime;
private int totalOverlaps = -1;
private double maxOverlap = -1;
private String state;
private Instant startTime;
......@@ -60,13 +61,21 @@ public class SimulationResult {
this.state = state;
}
public double getMaxOverlap() {
return maxOverlap;
}
public void setMaxOverlap(double maxOverlap) {
this.maxOverlap = maxOverlap;
}
public String[] getAsTableRow(){
String[] ret = new String[4];
String[] ret = new String[5];
ret[0] = scenarioName;
ret[1] = runTime.toString();
ret[2] = Integer.toString(totalOverlaps);
ret[3] = state;
ret[3] = Double.toString(maxOverlap);
ret[4] = state;
return ret;
}
......@@ -79,7 +88,8 @@ public class SimulationResult {
public static void addCsvHeader(StringBuilder sj, char dl){
sj.append("Scenario_Name").append(dl);
sj.append("Runtime").append(dl);
sj.append("Overlaps").append(dl);
sj.append("NumberOverlaps").append(dl);
sj.append("MaxOverlap").append(dl);
sj.append("State\n");
}
......
package org.vadere.simulator.projects.dataprocessing.datakey;
import org.jetbrains.annotations.NotNull;
import org.vadere.state.scenario.DynamicElement;
public class OverlapData {
......@@ -34,7 +35,15 @@ public class OverlapData {
return ped2Id;
}
public double getOverlap() {
return overlap;
}
public String[] toStrings(){
return new String[]{Double.toString(dist), Double.toString(overlap)};
}
public int maxDist(@NotNull OverlapData o) {
return Double.compare(overlap, o.getOverlap());
}
}
......@@ -9,13 +9,13 @@ import java.util.Objects;
public class TimestepPedestrianIdOverlapKey implements DataKey<TimestepPedestrianIdOverlapKey> {
private final int timeStep;
private final int pedId1;
private final int pedId2;
private final int pedId1; //smaller id
private final int pedId2; //bigger id
public TimestepPedestrianIdOverlapKey(int timeStep, int pedId1, int pedId2) {
public TimestepPedestrianIdOverlapKey(int timeStep, int pedA, int pedB) {
this.timeStep = timeStep;
this.pedId1 = pedId1;
this.pedId2 = pedId2;
this.pedId1 = (pedA <= pedB) ? pedA : pedB;
this.pedId2 = (pedA > pedB) ? pedA : pedB;
}
public static String[] getHeaders(){
......
......@@ -2,11 +2,14 @@ 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.OverlapData;
import org.vadere.state.attributes.processor.AttributesMaxOverlapProcessor;
import org.vadere.state.attributes.processor.AttributesProcessor;
import java.util.Optional;
import java.util.OptionalDouble;
/**
......@@ -20,7 +23,7 @@ import java.util.OptionalDouble;
@DataProcessorClass()
public class MaxOverlapProcessor extends DataProcessor<NoDataKey, Double> {
private PedestrianOverlapDistProcessor pedOverlapProc;
private PedestrianOverlapProcessor pedOverlapProc;
public MaxOverlapProcessor() {
......@@ -39,10 +42,11 @@ public class MaxOverlapProcessor extends DataProcessor<NoDataKey, Double> {
public void postLoop(final SimulationState state) {
this.pedOverlapProc.postLoop(state);
OptionalDouble maximumOverlap = this.pedOverlapProc.getValues().stream().filter(val -> val > 0).mapToDouble(val -> val.doubleValue()).max();
Optional<OverlapData> maximumOverlap = this.pedOverlapProc.getData().values().stream().max(OverlapData::maxDist);
if(maximumOverlap.isPresent()){
this.putValue(NoDataKey.key(),maximumOverlap.getAsDouble());
this.putValue(NoDataKey.key(),maximumOverlap.get().getOverlap());
/* // Uncomment if you want a info box to inform you about the maximum overlap
MaxOverlapProcessor.infoBox("Minimum distance between centers: " + maximumOverlap + " meters" , "Maximum Overlap");
......@@ -53,19 +57,16 @@ public class MaxOverlapProcessor extends DataProcessor<NoDataKey, Double> {
}
}
/* // Uncomment if you want a info box to inform you about the maximum overlap
public static void infoBox(String infoMessage, String titleBar)
{
JOptionPane.showMessageDialog(null, infoMessage, titleBar, JOptionPane.INFORMATION_MESSAGE);
public void postLoopAddResultInfo(final SimulationState state, SimulationResult result){
result.setMaxOverlap(this.getValue(NoDataKey.key()));
}
*/
@Override
public void init(final ProcessorManager manager) {
super.init(manager);
AttributesMaxOverlapProcessor att = (AttributesMaxOverlapProcessor) this.getAttributes();
this.pedOverlapProc = (PedestrianOverlapDistProcessor) manager.getProcessor(att.getPedestrianOverlapDistProcessorId());
this.pedOverlapProc = (PedestrianOverlapProcessor) manager.getProcessor(att.getPedestrianOverlapProcessorId());
}
......
......@@ -5,9 +5,12 @@ 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.OverlapData;
import org.vadere.state.attributes.processor.AttributesNumberOverlapsProcessor;
import org.vadere.state.attributes.processor.AttributesProcessor;
import java.util.Optional;
/**
* This processor counts the number of overlaps during a simulation run.
* The is commented code that can be used to show a info box if overlaps occured.
......@@ -36,13 +39,13 @@ public class NumberOverlapsProcessor extends DataProcessor<NoDataKey, Long> {
public void postLoop(final SimulationState state) {
this.pedOverlapProc.postLoop(state);
long numberOverlaps = this.pedOverlapProc.getData().size()/2;
long numberOverlaps = this.pedOverlapProc.getData().size();
this.putValue(NoDataKey.key(), numberOverlaps);
}
@Override
public void postLoopAddResultInfo(final SimulationState state, SimulationResult result){
result.setTotalOverlaps(this.pedOverlapProc.getData().size()/2);
result.setTotalOverlaps(this.pedOverlapProc.getData().size());
}
@Override
......
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.state.attributes.processor.AttributesMaxOverlapProcessor;
import org.vadere.state.scenario.Pedestrian;
import org.vadere.util.geometry.shapes.VPoint;
import java.util.*;
import java.util.stream.Stream;
/**
* This processor gives for each pedestrian - if at least one overlap occurs in this time step - the overlap with
* the closest other pedestrian. That is 2*radius - distance (between the centers of the pedestrians). That means, if
* several overlaps occur at the same timestep, only the largest one is shown.
* At the moment, the radius needs to be equal for all pedestrians in the simulation.
*
* @author Marion Gödel
*/
@DataProcessorClass()
public class PedestrianOverlapDistProcessor extends DataProcessor<TimestepPedestrianIdKey, Double> {
public PedestrianOverlapDistProcessor() {
super("overlap_dist");
}
@Override
protected void doUpdate(final SimulationState state) {
double 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, pedRadius)));
}
@Override
public void init(final ProcessorManager manager) {
super.init(manager);
}
private double calculateOverlaps(final Collection<Pedestrian> peds, Pedestrian ped, double pedRadius) {
VPoint pos = ped.getPosition();
Stream<Pedestrian> pedList = peds.stream().filter(p -> (!p.equals(ped)) ? p.getPosition().distance(pos) <= 2 * pedRadius: false);
List<Double> overlaps = new ArrayList<Double>();
pedList.forEach(p -> overlaps.add(2*pedRadius - p.getPosition().distance(pos)));
double overlapDist = (overlaps.isEmpty()) ? 0 : Collections.max(overlaps);
return overlapDist;
}
}
......@@ -22,17 +22,12 @@ public class JoltTransformV4toV5 extends JoltTransformation {
}
private JsonNode cleanupPedestrianOverlapProcessorAttribute(JsonNode node) throws MigrationException {
JsonNode processors = path(node, "processWriters/processors");
if (nodeIsArray(processors)) {
Iterator<JsonNode> iter = processors.iterator();
while (iter.hasNext()) {
JsonNode processor = iter.next();
String type = pathMustExist(processor, "type").asText();
if (type.equals("org.vadere.simulator.projects.dataprocessing.processor.PedestrianOverlapProcessor")) {
remove(processor, "attributes");
remove(processor, "attributesType");
}
}
Iterator<JsonNode> iter = iteratorProcessorsByType(node,"org.vadere.simulator.projects.dataprocessing.processor.PedestrianOverlapProcessor");
while (iter.hasNext()) {
JsonNode processor = iter.next();
String type = pathMustExist(processor, "type").asText();
remove(processor, "attributes");
remove(processor, "attributesType");
}
return node;
}
......
package org.vadere.simulator.projects.migration.jolttranformation;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import org.vadere.annotation.factories.migrationassistant.MigrationTransformation;
import org.vadere.simulator.entrypoints.Version;
import org.vadere.simulator.projects.migration.MigrationException;
import java.util.Iterator;
@MigrationTransformation(targetVersionLabel = "0.6")
public class JoltTransformV5toV6 extends JoltTransformation {
public JoltTransformV5toV6() {
super(Version.V0_6);
}
@Override
protected void initPostHooks() {
postTransformHooks.add(this::removePedestrianOverlapDistProcessor);
postTransformHooks.add(this::changePedestrianMaxOverlapProcessorAttributes);
postTransformHooks.add(JoltTransformV1toV2::sort);
}
private JsonNode removePedestrianOverlapDistProcessor(JsonNode node) throws MigrationException {
ArrayNode processors = (ArrayNode)pathMustExist(node, "processWriters/processors");
Iterator<JsonNode> iter = processors.iterator();
while (iter.hasNext()){
JsonNode p = iter.next();
String type = pathMustExist(p, "type").asText();
if (type.equals("org.vadere.simulator.projects.dataprocessing.processor.PedestrianOverlapDistProcessor")){
String processorId = pathMustExist(p, "id").asText();
Iterator<JsonNode> fileIter = iteratorFilesForProcessorId(node, processorId);
while (fileIter.hasNext()){
JsonNode file = fileIter.next();
arrayRemoveString((ArrayNode)pathMustExist(file, "processors"), processorId);
}
iter.remove();
}
}
return node;
}
private JsonNode changePedestrianMaxOverlapProcessorAttributes(JsonNode node) throws MigrationException {
Iterator<JsonNode> processIter = iteratorProcessorsByType(node,"org.vadere.simulator.projects.dataprocessing.processor.PedestrianOverlapProcessor");
while (processIter.hasNext()) {
JsonNode processor = processIter.next();
String pId = pathMustExist(processor, "id").asText();
// check all files the processor writes to for the correct Key.
Iterator<JsonNode> fileIter = iteratorFilesForProcessorId(node, pId);
boolean wrongFile = false;
while (fileIter.hasNext()){
JsonNode file = fileIter.next();
String fileType = pathMustExist(file, "type").asText();
if (!fileType.equals("org.vadere.simulator.projects.dataprocessing.outputfile.TimestepPedestrianIdOverlapOutputFile")){
arrayRemoveString((ArrayNode)pathMustExist(file, "processors"), pId);
wrongFile = true;
}
}
// if wrong mapping occurred (wrongFile == true) create a new outputFile an place the
// the pId in it.
if (wrongFile){
createNewOutputFile(node, "org.vadere.simulator.projects.dataprocessing.outputfile.TimestepPedestrianIdOverlapOutputFile", pId);
}
}
return node;
}
}
......@@ -25,7 +25,7 @@ import java.util.function.Function;
import java.util.function.Predicate;
public abstract class JoltTransformation {
public abstract class JoltTransformation implements JsonNodeExplorer{
protected final static Logger logger = Logger.getLogger(JoltTransformation.class);
private static ConcurrentHashMap<Version, JoltTransformation> transformations = new ConcurrentHashMap<>();
......@@ -136,10 +136,6 @@ public abstract class JoltTransformation {
protected abstract void initPostHooks();
protected void addToObjectNode(JsonNode node, String key, String value) {
((ObjectNode) node).put(key, value);
}
public ArrayList<PostTransformHook> getPostTransformHooks() {
return postTransformHooks;
......@@ -157,9 +153,9 @@ public abstract class JoltTransformation {
* @param key key to add to new HashMap
* @param children Specify Order on second level
*/
protected static void putObject(LinkedHashMap<Object, Object> target,
LinkedHashMap<Object, Object> source,
String key, String... children) throws MigrationException {
static void putObject(LinkedHashMap<Object, Object> target,
LinkedHashMap<Object, Object> source,
String key, String... children) throws MigrationException {
Object obj = source.get(key);
if (obj == null) {
......@@ -181,52 +177,5 @@ public abstract class JoltTransformation {
}
protected void remove(JsonNode root, String childName) throws MigrationException {
ObjectNode parent = (ObjectNode) root;
if (parent.remove(childName) == null) {
throw new MigrationException("Cannot delete childElement '" + childName + "' from parent " + root.asText());
}
}
protected JsonNode pathMustExist(JsonNode root, String path) throws MigrationException {
JsonNode ret = path(root, path);
if (ret.isMissingNode()) {
throw new MigrationException("Json Path Erro: The path '" + path +
"' should be accessible from " + root.asText());
}
return ret;
}
protected JsonNode path(JsonNode root, String path) {
String[] pathElements = path.split("/");
JsonNode ret = root;
for (String item : pathElements) {
ret = ret.path(item);
}
return ret;
}
protected boolean nodeIsArray(JsonNode node) {
return nodeNotEmptyAnd(node, n -> n.getNodeType() == JsonNodeType.ARRAY);
}
protected boolean nodeNotEmptyAnd(JsonNode node, Predicate<JsonNode> predicate) {
return !node.isMissingNode() && predicate.test(node);
}
protected Iterator<JsonNode> filterIterator(JsonNode root, Predicate<JsonNode> filter) {
return new Iterator<JsonNode>() {
@Override
public boolean hasNext() {
return false;
}
@Override
public JsonNode next() {
return null;
}
};
}
}
package org.vadere.simulator.projects.migration.jolttranformation;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.JsonNodeType;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.vadere.simulator.projects.migration.MigrationException;
import org.vadere.simulator.projects.migration.helper.JsonFilterIterator;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.function.Predicate;
public interface JsonNodeExplorer {
default void addToObjectNode(JsonNode node, String key, String value) {
((ObjectNode) node).put(key, value);
}
default void remove(JsonNode root, String childName) throws MigrationException {
ObjectNode parent = (ObjectNode) root;
if (parent.remove(childName) == null) {
throw new MigrationException("Cannot delete childElement '" + childName + "' from parent " + root.asText());
}
}
default JsonNode pathMustExist(JsonNode root, String path) throws MigrationException {
JsonNode ret = path(root, path);
if (ret.isMissingNode()) {
throw new MigrationException("Json Path Erro: The path '" + path +
"' should be accessible from " + root.asText());
}
return ret;
}
default JsonNode path(JsonNode root, String path) {
String[] pathElements = path.split("/");
JsonNode ret = root;
for (String item : pathElements) {
ret = ret.path(item);
}
return ret;
}
default boolean nodeIsArray(JsonNode node) {
return nodeNotEmptyAnd(node, n -> n.getNodeType() == JsonNodeType.ARRAY);
}
default boolean nodeNotEmptyAnd(JsonNode node, Predicate<JsonNode> predicate) {
return !node.isMissingNode() && predicate.test(node);
}
default Iterator<JsonNode> filterIterator(JsonNode root, Predicate<JsonNode> filter) {
return new Iterator<JsonNode>() {
@Override
public boolean hasNext() {
return false;
}
@Override
public JsonNode next() {
return null;
}
};
}
/**
* Create Iterator over all Processors with the given Type.
* @param node root of scenario
* @param processorType type of processors included in the iterator
* @return Iterator of JsonNodes representing a processor of the given type
* @throws MigrationException The scenario file must contain the path processWriters/processors
*/
default Iterator<JsonNode> iteratorProcessorsByType(JsonNode node, String processorType) throws MigrationException {
JsonNode processors = pathMustExist(node, "processWriters/processors");
return new JsonFilterIterator(processors, n -> {
String type = path(n, "type").asText();
return type.equals(processorType);
});
}
default ArrayList<JsonNode> getProcessorsByType(JsonNode node, String processorType) throws MigrationException {
Iterator<JsonNode> iter = iteratorProcessorsByType(node, processorType);
ArrayList<JsonNode> ret = new ArrayList<>();
while (iter.hasNext()){
JsonNode n = iter.next();
ret.add(n);
}
return ret;
}
/**
* Create Iterator over all files in the scenario which contain the
* specified id.
* @param node root of scenario
* @param id id of processor.
* @return Iterator of JsonNodes representing a file.
* @throws MigrationException The scenario file must contain the path processWriters/files
*/
default Iterator<JsonNode> iteratorFilesForProcessorId(JsonNode node, String id) throws MigrationException {
JsonNode files = pathMustExist(node, "processWriters/files");
return new JsonFilterIterator(files, n -> {
JsonNode processorIds = path(n, "processors");
if (processorIds.isMissingNode()){
return false;
} else {
for(final JsonNode pId: processorIds){
boolean ret = pId.asText().equals(id);
if (ret){
return true;
}
}
return false;
}
});
}
default ArrayList<JsonNode> getFilesForProcessorId(JsonNode node, String id) throws MigrationException {
Iterator<JsonNode> iter = iteratorFilesForProcessorId(node, id);
ArrayList<JsonNode> ret = new ArrayList<>();
while (iter.hasNext()){
JsonNode n = iter.next();
ret.add(n);
}
return ret;
}
default void arrayRemoveString(ArrayNode arrayNode, String val){
Iterator<JsonNode> iter = arrayNode.iterator();
while (iter.hasNext()){
JsonNode element = iter.next();
if (element.asText().equals(val)){
iter.remove();
}
}
}
default ArrayList<String> listOutputFileNames(JsonNode root) throws MigrationException {
JsonNode files = pathMustExist(root, "processWriters/files");
ArrayList<String> fileNames = new ArrayList<>();
for (JsonNode f : files){
fileNames.add(pathMustExist(f, "filename").asText());
}
return fileNames;
}
default void createNewOutputFile(JsonNode root, String type, String... pIds) throws MigrationException {
ArrayNode files = (ArrayNode)pathMustExist(root, "processWriters/files");
String fileName = "out";
int i = 1;
ArrayList<String> fileNames = listOutputFileNames(root);
while (fileNames.contains(fileName + i + ".txt")){
i++;
}
fileName = fileName + i + ".txt";
ObjectNode newFile = files.addObject();
newFile.put("type", type);
newFile.put("filename", fileName);
ArrayNode pArr = newFile.putArray("processors");
for (String pId : pIds) {
pArr.add(pId);
}
}
}
{
"name" : "test001",
"description" : "",
"release" : "0.5",
"commithash" : "warning: no commit hash",
"processWriters" : {
"files" : [ {
"type" : "org.vadere.simulator.projects.dataprocessing.outputfile.TimestepPedestrianIdOutputFile",
"filename" : "postvis.trajectories",
"processors" : [ 2, 6 ]
}, {
"type" : "org.vadere.simulator.projects.dataprocessing.outputfile.NoDataKeyOutputFile",
"filename" : "max_overlaps.txt",
"processors" : [ 5 ]
} ],
"processors" : [ {
"type" : "org.vadere.simulator.projects.dataprocessing.processor.PedestrianPositionProcessor",
"id" : 2
}, {
"type" : "org.vadere.simulator.projects.dataprocessing.processor.NumberOverlapsProcessor",
"id" : 5,
"attributesType" : "org.vadere.state.attributes.processor.AttributesNumberOverlapsProcessor",
"attributes" : {
"pedestrianOverlapProcessorId" : 6
}
}, {
"type" : "org.vadere.simulator.projects.dataprocessing.processor.PedestrianOverlapProcessor",
"id" : 6
} ],
"isTimestamped" : true
},
"scenario" : {
"mainModel" : "org.vadere.simulator.models.osm.OptimalStepsModel",
"attributesModel" : {
"org.vadere.state.attributes.models.AttributesFloorField" : {
"createMethod" : "HIGH_ACCURACY_FAST_MARCHING",
"potentialFieldResolution" : 0.1,
"obstacleGridPenalty" : 0.1,
"targetAttractionStrength" : 1.0,
"timeCostAttributes" : {
"standardDeviation" : 0.7,
"type" : "UNIT",
"obstacleDensityWeight" : 3.5,