Commit 85f5d96d authored by Benedikt Kleinmeier's avatar Benedikt Kleinmeier
Browse files

Merge branch 'add_change_target_scripted_cognition_model' into psychology

parents 38b5985f fbd7356e
Pipeline #233608 passed with stages
in 130 minutes and 32 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) {
super(time);