Commit 8b9b55a8 authored by Benedikt Kleinmeier's avatar Benedikt Kleinmeier
Browse files

Added "ChangeTargetScriptedCognitionModel.java" and corresponding stimulus to...

Added "ChangeTargetScriptedCognitionModel.java" and corresponding stimulus to change targets of agents based on simulation time
parent 91c1015e
Pipeline #227721 passed with stages
in 129 minutes and 39 seconds
{
"name" : "16-ScriptAgents-ChangeTargetScriptedCognitionModel",
"description" : "",
"release" : "1.11",
"processWriters" : {
"files" : [ {
"type" : "org.vadere.simulator.projects.dataprocessing.outputfile.EventtimePedestrianIdOutputFile",
"filename" : "postvis.traj",
"processors" : [ 1, 2 ]
}, {
"type" : "org.vadere.simulator.projects.dataprocessing.outputfile.TimestepPedestrianIdOverlapOutputFile",
"filename" : "overlaps.csv",
"processors" : [ 3 ]
}, {
"type" : "org.vadere.simulator.projects.dataprocessing.outputfile.NoDataKeyOutputFile",
"filename" : "overlapCount.txt",
"processors" : [ 4 ]
} ],
"processors" : [ {
"type" : "org.vadere.simulator.projects.dataprocessing.processor.FootStepProcessor",
"id" : 1
}, {
"type" : "org.vadere.simulator.projects.dataprocessing.processor.FootStepTargetIDProcessor",
"id" : 2
}, {
"type" : "org.vadere.simulator.projects.dataprocessing.processor.PedestrianOverlapProcessor",
"id" : 3
}, {
"type" : "org.vadere.simulator.projects.dataprocessing.processor.NumberOverlapsProcessor",
"id" : 4,
"attributesType" : "org.vadere.state.attributes.processor.AttributesNumberOverlapsProcessor",
"attributes" : {
"pedestrianOverlapProcessorId" : 3
}
} ],
"isTimestamped" : true,
"isWriteMetaData" : false
},
"scenario" : {
"mainModel" : "org.vadere.simulator.models.osm.OptimalStepsModel",
"attributesModel" : {
"org.vadere.state.attributes.models.AttributesOSM" : {
"stepCircleResolution" : 4,
"numberOfCircles" : 1,
"optimizationType" : "NELDER_MEAD",
"varyStepDirection" : true,
"movementType" : "ARBITRARY",
"stepLengthIntercept" : 0.4625,
"stepLengthSlopeSpeed" : 0.2345,
"stepLengthSD" : 0.036,
"movementThreshold" : 0.0,
"minStepLength" : 0.1,
"minimumStepLength" : true,
"maxStepDuration" : 1.7976931348623157E308,
"dynamicStepLength" : true,
"updateType" : "EVENT_DRIVEN",
"seeSmallWalls" : false,
"targetPotentialModel" : "org.vadere.simulator.models.potential.fields.PotentialFieldTargetGrid",
"pedestrianPotentialModel" : "org.vadere.simulator.models.potential.PotentialFieldPedestrianCompactSoftshell",
"obstaclePotentialModel" : "org.vadere.simulator.models.potential.PotentialFieldObstacleCompactSoftshell",
"submodels" : [ ]
},
"org.vadere.state.attributes.models.AttributesPotentialCompactSoftshell" : {
"pedPotentialIntimateSpaceWidth" : 0.45,
"pedPotentialPersonalSpaceWidth" : 1.2,
"pedPotentialHeight" : 50.0,
"obstPotentialWidth" : 0.8,
"obstPotentialHeight" : 6.0,
"intimateSpaceFactor" : 1.2,
"personalSpacePower" : 1,
"intimateSpacePower" : 1
},
"org.vadere.state.attributes.models.AttributesFloorField" : {
"createMethod" : "HIGH_ACCURACY_FAST_MARCHING",
"potentialFieldResolution" : 0.1,
"obstacleGridPenalty" : 0.1,
"targetAttractionStrength" : 1.0,
"cacheType" : "NO_CACHE",
"cacheDir" : "",
"timeCostAttributes" : {
"standardDeviation" : 0.7,
"type" : "UNIT",
"obstacleDensityWeight" : 3.5,
"pedestrianSameTargetDensityWeight" : 3.5,
"pedestrianOtherTargetDensityWeight" : 3.5,
"pedestrianWeight" : 3.5,
"queueWidthLoading" : 1.0,
"pedestrianDynamicWeight" : 6.0,
"loadingType" : "CONSTANT",
"width" : 0.2,
"height" : 1.0
}
}
},
"attributesSimulation" : {
"finishTime" : 30.0,
"simTimeStepLength" : 0.4,
"realTimeSimTimeRatio" : 0.1,
"writeSimulationData" : true,
"visualizationEnabled" : true,
"printFPS" : false,
"digitsPerCoordinate" : 2,
"useFixedSeed" : true,
"fixedSeed" : 2810487519014576514,
"simulationSeed" : 0
},
"attributesPsychology" : {
"usePsychologyLayer" : true,
"psychologyLayer" : {
"perception" : "SimplePerceptionModel",
"cognition" : "ChangeTargetScriptedCognitionModel"
}
},
"topography" : {
"attributes" : {
"bounds" : {
"x" : 0.0,
"y" : 0.0,
"width" : 10.0,
"height" : 20.0
},
"boundingBoxWidth" : 0.5,
"bounded" : true,
"referenceCoordinateSystem" : null
},
"obstacles" : [ ],
"measurementAreas" : [ ],
"stairs" : [ ],
"targets" : [ {
"id" : 4,
"absorbing" : true,
"shape" : {
"x" : 8.0,
"y" : 18.0,
"width" : 1.0,
"height" : 1.0,
"type" : "RECTANGLE"
},
"waitingTime" : 0.0,
"waitingTimeYellowPhase" : 0.0,
"parallelWaiters" : 0,
"individualWaiting" : true,
"deletionDistance" : 0.1,
"startingWithRedLight" : false,
"nextSpeed" : -1.0
}, {
"id" : 1,
"absorbing" : true,
"shape" : {
"x" : 0.9,
"y" : 1.0,
"width" : 1.0,
"height" : 1.0,
"type" : "RECTANGLE"
},
"waitingTime" : 0.0,
"waitingTimeYellowPhase" : 0.0,
"parallelWaiters" : 0,
"individualWaiting" : true,
"deletionDistance" : 0.1,
"startingWithRedLight" : false,
"nextSpeed" : -1.0
}, {
"id" : 2,
"absorbing" : true,
"shape" : {
"x" : 3.0,
"y" : 1.0,
"width" : 1.0,
"height" : 1.0,
"type" : "RECTANGLE"
},
"waitingTime" : 0.0,
"waitingTimeYellowPhase" : 0.0,
"parallelWaiters" : 0,
"individualWaiting" : true,
"deletionDistance" : 0.1,
"startingWithRedLight" : false,
"nextSpeed" : -1.0
}, {
"id" : 3,
"absorbing" : true,
"shape" : {
"x" : 5.0,
"y" : 1.0,
"width" : 1.0,
"height" : 1.0,
"type" : "RECTANGLE"
},
"waitingTime" : 0.0,
"waitingTimeYellowPhase" : 0.0,
"parallelWaiters" : 0,
"individualWaiting" : true,
"deletionDistance" : 0.1,
"startingWithRedLight" : false,
"nextSpeed" : -1.0
} ],
"targetChangers" : [ ],
"absorbingAreas" : [ ],
"sources" : [ {
"id" : 1,
"shape" : {
"x" : 1.0,
"y" : 18.0,
"width" : 1.0,
"height" : 1.0,
"type" : "RECTANGLE"
},
"interSpawnTimeDistribution" : "org.vadere.state.scenario.ConstantDistribution",
"distributionParameters" : [ 1.0 ],
"spawnNumber" : 4,
"maxSpawnNumberTotal" : -1,
"startTime" : 0.0,
"endTime" : 0.0,
"spawnAtRandomPositions" : false,
"spawnAtGridPositionsCA" : false,
"useFreeSpaceOnly" : true,
"targetIds" : [ 1 ],
"groupSizeDistribution" : [ 1.0 ],
"dynamicElementType" : "PEDESTRIAN"
}, {
"id" : 2,
"shape" : {
"x" : 3.0,
"y" : 18.0,
"width" : 1.0,
"height" : 1.0,
"type" : "RECTANGLE"
},
"interSpawnTimeDistribution" : "org.vadere.state.scenario.ConstantDistribution",
"distributionParameters" : [ 1.0 ],
"spawnNumber" : 4,
"maxSpawnNumberTotal" : -1,
"startTime" : 0.0,
"endTime" : 0.0,
"spawnAtRandomPositions" : false,
"spawnAtGridPositionsCA" : false,
"useFreeSpaceOnly" : true,
"targetIds" : [ 2 ],
"groupSizeDistribution" : [ 1.0 ],
"dynamicElementType" : "PEDESTRIAN"
}, {
"id" : 3,
"shape" : {
"x" : 5.0,
"y" : 18.0,
"width" : 1.0,
"height" : 1.0,
"type" : "RECTANGLE"
},
"interSpawnTimeDistribution" : "org.vadere.state.scenario.ConstantDistribution",
"distributionParameters" : [ 1.0 ],
"spawnNumber" : 4,
"maxSpawnNumberTotal" : -1,
"startTime" : 0.0,
"endTime" : 0.0,
"spawnAtRandomPositions" : false,
"spawnAtGridPositionsCA" : false,
"useFreeSpaceOnly" : true,
"targetIds" : [ 3 ],
"groupSizeDistribution" : [ 1.0 ],
"dynamicElementType" : "PEDESTRIAN"
} ],
"dynamicElements" : [ ],
"attributesPedestrian" : {
"radius" : 0.2,
"densityDependentSpeed" : false,
"speedDistributionMean" : 1.34,
"speedDistributionStandardDeviation" : 0.26,
"minimumSpeed" : 0.5,
"maximumSpeed" : 2.2,
"acceleration" : 2.0,
"footstepHistorySize" : 4,
"searchRadius" : 1.0,
"walkingDirectionCalculation" : "BY_TARGET_CENTER",
"walkingDirectionSameIfAngleLessOrEqual" : 45.0
},
"teleporter" : null,
"attributesCar" : {
"id" : -1,
"radius" : 0.2,
"densityDependentSpeed" : false,
"speedDistributionMean" : 1.34,
"speedDistributionStandardDeviation" : 0.26,
"minimumSpeed" : 0.5,
"maximumSpeed" : 2.2,
"acceleration" : 2.0,
"footstepHistorySize" : 4,
"searchRadius" : 1.0,
"walkingDirectionCalculation" : "BY_TARGET_CENTER",
"walkingDirectionSameIfAngleLessOrEqual" : 45.0,
"length" : 4.5,
"width" : 1.7,
"direction" : {
"x" : 1.0,
"y" : 0.0
}
}
},
"stimulusInfos" : [ {
"timeframe" : {
"startTime" : 0.0,
"endTime" : 0.4,
"repeat" : true,
"waitTimeBetweenRepetition" : 0.0
},
"stimuli" : [ {
"type" : "ChangeTargetScripted",
"allowedTimeDelta" : 0.4,
"changeRemainingPedestrians" : false,
"originalTargetIds" : [ 1, 2 ],
"newTargetIds" : [ 4, 4 ],
"simTimesToChangeTarget" : [ 4.0, 8.0 ],
"totalAgentsToChangeTarget" : [ 1, 2 ]
} ]
} ]
}
}
package org.vadere.simulator.control.psychology.cognition;
import org.vadere.state.psychology.cognition.SelfCategory;
import org.vadere.state.psychology.perception.types.ChangeTargetScripted;
import org.vadere.state.scenario.Pedestrian;
import org.vadere.state.scenario.Topography;
import org.vadere.state.simulation.FootstepHistory;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import java.util.stream.Collectors;
/**
* The {@link ChangeTargetScriptedCognitionModel} changes the target id of agents. The stimulus
* {@link org.vadere.state.psychology.perception.types.ChangeTargetScripted} describes at which
* simulation time agents should change their target.
*
* The target id is changed directly here at cognition layer and on locomotion layer an agent just performs a step.
*/
public class ChangeTargetScriptedCognitionModel implements ICognitionModel {
private Topography topography;
@Override
public void initialize(Topography topography) {
this.topography = topography;
}
@Override
public void update(Collection<Pedestrian> pedestrians) {
// Watch out: "allMatch()" returns true on empty list!
if (pedestrians.stream().allMatch(pedestrian -> pedestrian.getMostImportantStimulus() instanceof ChangeTargetScripted)) {
if (pedestrians.isEmpty() == false) {
ChangeTargetScripted changeTargetScripted = (ChangeTargetScripted) pedestrians.iterator().next().getMostImportantStimulus();
changeTargetsAccordingToStimulus(changeTargetScripted, pedestrians);
}
}
pedestrians.stream().forEach(pedestrian -> pedestrian.setSelfCategory(SelfCategory.TARGET_ORIENTED));
}
private void changeTargetsAccordingToStimulus(ChangeTargetScripted changeTargetScripted, Collection<Pedestrian> pedestrians) {
int activeIndex = getActiveIndexFromStimulusList(changeTargetScripted);
if (activeIndex >= 0) {
Integer nextTarget = changeTargetScripted.getNewTargetIds().get(activeIndex);
Integer totalAgentsToChange = changeTargetScripted.getTotalAgentsToChangeTarget().get(activeIndex);
LinkedList<Integer> originalTargetIds = changeTargetScripted.getOriginalTargetIds();
boolean changeRemainingPedestrians = changeTargetScripted.getChangeRemainingPedestrians();
changeTargetsOfPedestrians(pedestrians, nextTarget, totalAgentsToChange, originalTargetIds, changeRemainingPedestrians);
}
}
private int getActiveIndexFromStimulusList(ChangeTargetScripted changeTargetScripted) {
LinkedList<Double> simTimesToChangeTarget = changeTargetScripted.getSimTimesToChangeTarget();
double allowedTimeDelta = changeTargetScripted.getAllowedTimeDelta();
double currentSimTimeInSec = changeTargetScripted.getTime();
int activeIndex = -1;
for (int i = 0; i < simTimesToChangeTarget.size(); i++) {
Double currentSimTimeFromList = simTimesToChangeTarget.get(i);
double timeDelta = currentSimTimeInSec - currentSimTimeFromList;
// Use "timeDelta >= 0" to ensure that target change does not happen before the definition from list.
if (timeDelta >= 0 && timeDelta <= allowedTimeDelta) {
activeIndex = i;
break;
}
}
return activeIndex;
}
private void changeTargetsOfPedestrians(Collection<Pedestrian> pedestrians, int nextTarget, int totalAgentsToChange, LinkedList<Integer> originalTargets, boolean changeRemainingPedestrians) {
List<Pedestrian> originalPedsToChange = pedestrians.stream()
.filter(pedestrian -> originalTargets.contains(pedestrian.getNextTargetId()) == true)
.collect(Collectors.toList());
List<Pedestrian> remainingPedsToChange = pedestrians.stream()
.filter(pedestrian -> originalTargets.contains(pedestrian.getNextTargetId()) == false)
.collect(Collectors.toList());
boolean nextTargetIsAgent = false;
List<Pedestrian> originalPedsToChangeSubList = (totalAgentsToChange <= originalPedsToChange.size()) ? originalPedsToChange.subList(0, totalAgentsToChange) : originalPedsToChange;
originalPedsToChangeSubList.stream().forEach(pedestrian -> pedestrian.setSingleTarget(nextTarget, nextTargetIsAgent));
if (changeRemainingPedestrians) {
remainingPedsToChange.stream().forEach(pedestrian -> pedestrian.setSingleTarget(nextTarget, nextTargetIsAgent));
}
}
}
......@@ -12,7 +12,7 @@ import java.util.stream.Collectors;
/**
* Use a very simple strategy to rank stimulus priority:
*
* ChangeTarget > Threat > Wait > WaitInArea > ElapsedTime
* ChangeTargetScripted > ChangeTarget > Threat > Wait > WaitInArea > ElapsedTime
*/
public class SimplePerceptionModel implements IPerceptionModel {
......@@ -43,8 +43,11 @@ public class SimplePerceptionModel implements IPerceptionModel {
List<Stimulus> waitInAreaStimuli = stimuli.stream().filter(stimulus -> stimulus instanceof WaitInArea).collect(Collectors.toList());
List<Stimulus> threatStimuli = stimuli.stream().filter(stimulus -> stimulus instanceof Threat).collect(Collectors.toList());
List<Stimulus> changeTargetStimuli = stimuli.stream().filter(stimulus -> stimulus instanceof ChangeTarget).collect(Collectors.toList());
List<Stimulus> changeTargetScriptedStimuli = stimuli.stream().filter(stimulus -> stimulus instanceof ChangeTargetScripted).collect(Collectors.toList());
if (changeTargetStimuli.size() >= 1) {
if (changeTargetScriptedStimuli.size() >= 1) {
mostImportantStimulus = changeTargetScriptedStimuli.get(0);
} else if (changeTargetStimuli.size() >= 1) {
mostImportantStimulus = changeTargetStimuli.get(0);
} else if (threatStimuli.size() >= 1) {
Stimulus closestThreat = selectClosestAndPerceptibleThreat(pedestrian, threatStimuli);
......
......@@ -95,6 +95,28 @@ public class SimplePerceptionModelTest {
pedestrians.forEach(pedestrian -> assertTrue(expectedStimulus == pedestrian.getMostImportantStimulus()));
}
@Test
public void updateRanksChangeTargetScriptedHigherThanElapsedTime() {
Topography topography = createTopography();
List<Pedestrian> pedestrians = createPedestrians(2);
List<Stimulus> stimuli = new ArrayList<>();
Stimulus expectedStimulus = new ChangeTargetScripted();
stimuli.add(new ElapsedTime());
stimuli.add(expectedStimulus);
SimplePerceptionModel simplePerceptionModel = new SimplePerceptionModel();
simplePerceptionModel.initialize(topography);
pedestrians.forEach(pedestrian -> assertNull(pedestrian.getMostImportantStimulus()));
simplePerceptionModel.update(pedestrians, stimuli);
// Use "==" to compare if it is the same reference!
pedestrians.forEach(pedestrian -> assertTrue(expectedStimulus == pedestrian.getMostImportantStimulus()));
}
@Test
public void updateRanksChangeTargetHigherThanElapsedTime() {
Topography topography = createTopography();
......@@ -230,4 +252,27 @@ public class SimplePerceptionModelTest {
assertEquals(expectedTime, pedestrians.get(0).getMostImportantStimulus().getTime(), ALLOWED_DOUBLE_ERROR);
assertEquals(expectedElapsedTime.getTime(), pedestrians.get(1).getMostImportantStimulus().getTime(), ALLOWED_DOUBLE_ERROR);
}
@Test
public void updateRanksChangeTargetScriptedHigherThanChangeTarget() {
Topography topography = createTopography();
List<Pedestrian> pedestrians = createPedestrians(2);
List<Stimulus> stimuli = new ArrayList<>();
Stimulus expectedStimulus = new ChangeTargetScripted();
stimuli.add(new ElapsedTime());
stimuli.add(new ChangeTarget());
stimuli.add(expectedStimulus);
SimplePerceptionModel simplePerceptionModel = new SimplePerceptionModel();
simplePerceptionModel.initialize(topography);
pedestrians.forEach(pedestrian -> assertNull(pedestrian.getMostImportantStimulus()));
simplePerceptionModel.update(pedestrians, stimuli);
// Use "==" to compare if it is the same reference!
pedestrians.forEach(pedestrian -> assertTrue(expectedStimulus == pedestrian.getMostImportantStimulus()));
}
}
\ No newline at end of file
......@@ -30,6 +30,8 @@ public class StimulusPresettings {
new Threat(),
new Wait(),
new WaitInArea(0, new VRectangle(0, 0, 10, 10)),
new ChangeTarget(),
new ChangeTargetScripted()
};
for (Stimulus stimulus : stimuliToUse) {
......
package org.vadere.state.psychology.perception.types;
import java.util.LinkedList;
/**
* Class signals agents to change their targets.
*
* This stimulus allows to script
* <ul>
* <li>when agents change their target to a new target.</li>
* <li>how much agents should change their target to a new target.</li>
* </ul>
*
* For instance, a stimulus description looks like this:
* <ul>
* <li>allowedTimeDelta = 1.0</li>
* <li>changeRemainingPedestrians = true</li>
* <li>originalTargetIds = [1, 2]</li>
* <li>newTargetIds = [3, 4]</li>
* <li>simTimesToChangeTarget = [10.0, 20.0]</li>
* <li>totalAgentsToChangeTarget = [1, 2]</li>
* </ul>
*
* On the cognition layer, this leads to following actions:
* <ul>
* <li>At sim time 10.0 second, for 1 agent with target id 1 or 2 change target id to 3.</li>
* <li>At sim time 20.0 second, for 2 agents with target id 1 or 2 change target id to 4.</li>
* <li>At each sim time from "simTimesToChangeTarget", change also the target of all remaining agents
* (i.e., whose target id is not in list "originalTargetIds") if "changeRemainingPedestrians = true".
* For instance, at sim time 10.0 second the target id of agent a1 changed from 1 to 3 and at
* sim time 20.0 the target id is changed from 3 to 4 (since 3 is not in list [1, 2].</li>
* </ul>
*
* Note: "allowedTimeDelta" is necessary to make sure that stimulus is injected properly. For instance, if
* "simTimeStepLength = 0.4" the simulated times are [0.0, 0.4, 0.8, 1.2, ...]. If "ChangeTargetScripted" should
* be injected at "start = 1.0" and "end = 1.1" this would mean it could not be injected because the
* "simTimeStepLength" is too coarse. Setting "allowedTimeDelta = 0.2" causes that the stimulus is
* injected at "simTime = 1.2".
*/
public class ChangeTargetScripted extends Stimulus {
// Member Variables
private double allowedTimeDelta;
private boolean changeRemainingPedestrians;
private LinkedList<Integer> originalTargetIds;
private LinkedList<Integer> newTargetIds;
private LinkedList<Double> simTimesToChangeTarget;
private LinkedList<Integer> totalAgentsToChangeTarget;
// Constructors
// Default constructor required for JSON de-/serialization.
public ChangeTargetScripted() { super(); }
public ChangeTargetScripted(double time) {