Commit b564e158 authored by Benedikt Zoennchen's avatar Benedikt Zoennchen
Browse files

Merge branch 'dev/removeTimeCredit' into 'master'

Dev/remove time credit

See merge request !98
parents 27e988e5 eaadd70c
Pipeline #186947 passed with stages
in 139 minutes and 17 seconds
......@@ -67,12 +67,9 @@ public class OSMBehaviorController {
assert stepEndTime >= stepStartTime && stepEndTime >= 0.0 && stepStartTime >= 0.0 : stepEndTime + "<" + stepStartTime;
if (nextPosition.equals(currentPosition)) {
pedestrian.setTimeCredit(0);
pedestrian.setVelocity(new Vector2D(0, 0));
} else {
pedestrian.setTimeCredit(pedestrian.getTimeCredit() - pedestrian.getDurationNextStep());
pedestrian.setPosition(nextPosition);
synchronized (topography) {
topography.moveElement(pedestrian, currentPosition);
......@@ -91,10 +88,26 @@ public class OSMBehaviorController {
pedestrian.getFootstepHistory().add(currentFootstep);
}
/**
* This operation undo the last foot step of an agent. This is required to resolve conflicts by the {@link org.vadere.simulator.models.osm.updateScheme.UpdateSchemeParallel}.
*
* @param pedestrian the agent
* @param topography the topography
*/
public void undoStep(@NotNull final PedestrianOSM pedestrian, @NotNull final Topography topography) {
FootStep footStep = pedestrian.getTrajectory().removeLast();
pedestrian.getFootstepHistory().removeLast();
pedestrian.setPosition(footStep.getStart());
synchronized (topography) {
topography.moveElement(pedestrian, footStep.getEnd());
}
pedestrian.setVelocity(new Vector2D(0, 0));
}
public void wait(PedestrianOSM pedestrian, double timeStepInSec) {
// Satisfy event-driven and sequential update scheme.
pedestrian.setTimeOfNextStep(pedestrian.getTimeOfNextStep() + timeStepInSec);
pedestrian.setTimeCredit(0);
}
// Watch out: A bang event changes only the "CombinedPotentialStrategy".
......@@ -319,12 +332,5 @@ public class OSMBehaviorController {
pedestrian1.setTimeOfNextStep(endTimeStep);
pedestrian2.setTimeOfNextStep(endTimeStep);
// TODO:
// "makeStep()" already invokes
// "pedestrian.setTimeCredit(pedestrian.getTimeCredit() - pedestrian.getDurationNextStep())"
// => Ask BZ if is it really necessary to call it twice (and subtract duration twice)?
pedestrian1.setTimeCredit(pedestrian1.getTimeCredit() - durationStep);
pedestrian2.setTimeCredit(pedestrian1.getTimeCredit());
}
}
......@@ -51,8 +51,6 @@ public class PedestrianOSM extends Pedestrian {
private VPoint nextPosition;
private VPoint lastPosition;
// for unit time clock update...
private double timeCredit;
// for event driven update...
private double timeOfNextStep;
......@@ -324,14 +322,6 @@ public class PedestrianOSM extends Pedestrian {
this.lastPosition = lastPosition;
}
public double getTimeCredit() {
return timeCredit;
}
public void setTimeCredit(double timeCredit) {
this.timeCredit = timeCredit;
}
public void refreshRelevantPedestrians() {
VCircle reachableArea = new VCircle(getPosition(), getFreeFlowStepSize());
setRelevantPedestrians(potentialFieldPedestrian.getRelevantAgents(reachableArea, this, getTopography()));
......
......@@ -40,7 +40,7 @@ public class UpdateSchemeCLEventDriven extends UpdateSchemeParallel {
if (pedestrian.getTimeCredit() > pedestrian.getDurationNextStep()) {
pedestrian.updateNextPosition();
movedPedestrians.add(pedestrian);
movePedestrians.add(pedestrian);
}
*/
......@@ -48,7 +48,7 @@ public class UpdateSchemeCLEventDriven extends UpdateSchemeParallel {
public void update(double timeStepInSec, double currentTimeInSec) {
try {
clearStrides(topography);
movedPedestrians.clear();
movePedestrians.clear();
List<PedestrianOSM> pedestrianOSMList = CollectionUtils.select(topography.getElements(Pedestrian.class), PedestrianOSM.class);
......
......@@ -4,8 +4,6 @@ package org.vadere.simulator.models.osm.updateScheme;
import org.jetbrains.annotations.NotNull;
import org.vadere.simulator.models.osm.PedestrianOSM;
import org.vadere.simulator.models.osm.opencl.CLParallelOSMLocalMem;
import org.vadere.simulator.models.osm.opencl.CLParallelOptimalStepsModel;
import org.vadere.state.attributes.models.AttributesPotentialCompact;
import org.vadere.state.scenario.Pedestrian;
import org.vadere.state.scenario.Topography;
import org.vadere.util.geometry.shapes.VPoint;
......@@ -14,9 +12,7 @@ import org.vadere.util.logging.Logger;
import org.vadere.util.opencl.OpenCLException;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.Future;
/**
* @author Benedikt Zoennchen
......@@ -39,7 +35,7 @@ public class UpdateSchemeCLParallel extends UpdateSchemeParallel {
if (pedestrian.getTimeCredit() > pedestrian.getDurationNextStep()) {
pedestrian.updateNextPosition();
movedPedestrians.add(pedestrian);
movePedestrians.add(pedestrian);
}
*/
......@@ -47,7 +43,7 @@ public class UpdateSchemeCLParallel extends UpdateSchemeParallel {
public void update(double timeStepInSec, double currentTimeInSec) {
try {
clearStrides(topography);
movedPedestrians.clear();
movePedestrians.clear();
List<PedestrianOSM> pedestrianOSMList = CollectionUtils.select(topography.getElements(Pedestrian.class), PedestrianOSM.class);
......@@ -82,7 +78,7 @@ public class UpdateSchemeCLParallel extends UpdateSchemeParallel {
//if (pedestrian.getTimeCredit() > pedestrian.getDurationNextStep()) {
//pedestrian.setNextPosition(result.get(i));
movePedestrian(topography, pedestrian, pedestrian.getPosition(), result.get(i));
//movedPedestrians.add(pedestrian);
//movePedestrians.add(pedestrian);
//}
}
......
......@@ -29,9 +29,7 @@ public class UpdateSchemeEventDriven implements UpdateSchemeOSM {
@Override
public void update(final double timeStepInSec, final double currentTimeInSec) {
clearStrides(topography);
if(!pedestrianEventsQueue.isEmpty()) {
// event driven update ignores time credits!
while (pedestrianEventsQueue.peek().getTimeOfNextStep() < currentTimeInSec) {
......
......@@ -117,50 +117,4 @@ public interface UpdateSchemeOSM extends DynamicElementRemoveListener<Pedestrian
topography.moveElement(pedestrian, from);
}
}
/**
* Prepare move of pedestrian inside the topography. The pedestrian object already has the new
* location (Vpoint to) stored within its position attribute. This method only informs the
* topography object of the change in state.
*
* !IMPORTANT! this function calls movePedestrian which must be called ONLY ONCE for each
* pedestrian for each position. To allow preformat selection of a pedestrian the managing
* destructure is not idempotent (cannot be applied multiple time without changing result).
*
* @param topography manages simulation data
* @param pedestrian moving pedestrian. This object's position is already set.
* @param stepDuration time in seconds used for the step.
*/
default void makeStep(@NotNull final Topography topography, @NotNull final PedestrianOSM pedestrian, final double stepDuration) {
VPoint currentPosition = pedestrian.getPosition();
VPoint nextPosition = pedestrian.getNextPosition();
// start time
double timeOfNextStep = pedestrian.getTimeOfNextStep();
// end time
double entTimeOfStep = pedestrian.getTimeOfNextStep() + pedestrian.getDurationNextStep();
if (nextPosition.equals(currentPosition)) {
pedestrian.setTimeCredit(0);
pedestrian.setVelocity(new Vector2D(0, 0));
} else {
pedestrian.setTimeCredit(pedestrian.getTimeCredit() - pedestrian.getDurationNextStep());
movePedestrian(topography, pedestrian, pedestrian.getPosition(), nextPosition);
// compute velocity by forward difference
Vector2D pedVelocity = new Vector2D(nextPosition.x - currentPosition.x, nextPosition.y - currentPosition.y).multiply(1.0 / stepDuration);
pedestrian.setVelocity(pedVelocity);
}
/**
* strides and foot steps have no influence on the simulation itself, i.e. they are saved to analyse trajectories
*/
pedestrian.getStrides().add(Pair.of(currentPosition.distance(nextPosition), timeOfNextStep));
FootStep currentFootstep = new FootStep(currentPosition, nextPosition, timeOfNextStep, entTimeOfStep);
pedestrian.getTrajectory().add(currentFootstep);
pedestrian.getFootstepHistory().add(currentFootstep);
}
}
......@@ -11,23 +11,39 @@ import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import org.jetbrains.annotations.NotNull;
import org.vadere.simulator.models.osm.OSMBehaviorController;
import org.vadere.simulator.models.osm.PedestrianOSM;
import org.vadere.state.psychology.cognition.SelfCategory;
import org.vadere.state.psychology.perception.types.ElapsedTime;
import org.vadere.state.scenario.Agent;
import org.vadere.state.scenario.Pedestrian;
import org.vadere.state.scenario.Topography;
import org.vadere.util.geometry.shapes.Vector2D;
import org.vadere.util.io.CollectionUtils;
import org.vadere.util.logging.Logger;
/**
* TODO: should also use OSMBehaviorController.makeStep !
* The implementation of the parallel update scheme described in 'How update schemes influence crowd simulations' i.e. seitz-2014b.
* The implementation is not based on the time credit concept but on event times similar to the event driven update scheme.
* The difference is that all events which starts within a time span of <tt>currentTimeInSec</tt> - <tt>timeStepInSec</tt> and <tt>currentTimeInSec</tt>
* will be performed in parallel on the bases of the situation (i.e. agents position) at <tt>currentTimeInSec</tt> - <tt>timeStepInSec</tt>.
*/
public class UpdateSchemeParallel implements UpdateSchemeOSM {
private static final int NUMBER_OF_THREADS = 8;
private static Logger logger = Logger.getLogger(UpdateSchemeParallel.class);
protected final ExecutorService executorService;
protected final Topography topography;
protected final Set<Pedestrian> movedPedestrians;
/**
* marks an agent that will move in the time span.
*/
protected final Set<Pedestrian> movePedestrians;
/**
* marks an agent which shall move back because of conflicts.
*/
protected final Set<Pedestrian> undoPedestrians;
private final OSMBehaviorController osmBehaviorController;
static {
logger.setDebug();
......@@ -35,38 +51,42 @@ public class UpdateSchemeParallel implements UpdateSchemeOSM {
public UpdateSchemeParallel(@NotNull final Topography topography) {
this.topography = topography;
this.executorService = Executors.newFixedThreadPool(8);
this.movedPedestrians = new HashSet<>();
this.executorService = Executors.newFixedThreadPool(NUMBER_OF_THREADS);
this.movePedestrians = new HashSet<>();
this.undoPedestrians = new HashSet<>();
this.osmBehaviorController = new OSMBehaviorController();
}
@Override
public void update(double timeStepInSec, double currentTimeInSec) {
clearStrides(topography);
movedPedestrians.clear();
CallMethod[] callMethods = {CallMethod.SEEK, CallMethod.MOVE, CallMethod.CONFLICTS, CallMethod.STEPS};
List<Future<?>> futures;
do {
movePedestrians.clear();
undoPedestrians.clear();
CallMethod[] callMethods = {CallMethod.SEEK, CallMethod.MOVE, CallMethod.CONFLICTS, CallMethod.STEPS};
List<Future<?>> futures;
for (CallMethod callMethod : callMethods) {
long ms = 0;
if(callMethod == CallMethod.SEEK) {
ms = System.currentTimeMillis();
}
for (CallMethod callMethod : callMethods) {
long ms = 0;
if(callMethod == CallMethod.SEEK) {
ms = System.currentTimeMillis();
}
futures = new LinkedList<>();
for (final PedestrianOSM pedestrian : CollectionUtils.select(topography.getElements(Pedestrian.class), PedestrianOSM.class)) {
Runnable worker = () -> update(pedestrian, timeStepInSec, currentTimeInSec, callMethod);
futures.add(executorService.submit(worker));
}
collectFutures(futures);
futures = new LinkedList<>();
for (final PedestrianOSM pedestrian : CollectionUtils.select(topography.getElements(Pedestrian.class), PedestrianOSM.class)) {
Runnable worker = () -> update(pedestrian, timeStepInSec, currentTimeInSec, callMethod);
futures.add(executorService.submit(worker));
}
collectFutures(futures);
if(callMethod == CallMethod.SEEK) {
ms = System.currentTimeMillis() - ms;
logger.debug("runtime for next step computation = " + ms + " [ms]");
}
if(callMethod == CallMethod.SEEK) {
ms = System.currentTimeMillis() - ms;
logger.debug("runtime for next step computation = " + ms + " [ms]");
}
}
} while (!movePedestrians.isEmpty());
}
protected void collectFutures(final List<Future<?>> futures) {
......@@ -83,22 +103,24 @@ public class UpdateSchemeParallel implements UpdateSchemeOSM {
}
}
protected void update(@NotNull final PedestrianOSM pedestrian, final double timeStepInSec, double currentTimeInSec, CallMethod callMethod) {
pedestrian.clearStrides();
protected void update(@NotNull final PedestrianOSM pedestrian, final double timeStepInSec, final double currentTimeInSec, CallMethod callMethod) {
// At the moment no other events are supported for the parallel update scheme!
assert pedestrian.getMostImportantStimulus() instanceof ElapsedTime && pedestrian.getSelfCategory() == SelfCategory.TARGET_ORIENTED;
switch (callMethod) {
case SEEK:
updateParallelSeek(pedestrian, timeStepInSec);
updateParallelSeek(pedestrian, currentTimeInSec, timeStepInSec);
break;
case RETRY:
updateParallelSeek(pedestrian,0.0);
updateParallelSeek(pedestrian, currentTimeInSec,0.0);
case MOVE:
updateParallelMove(pedestrian);
updateParallelMove(pedestrian, timeStepInSec);
break;
case CONFLICTS:
updateParallelConflicts(pedestrian);
break;
case STEPS:
updateParallelSteps(pedestrian, timeStepInSec);
updateParallelSteps(pedestrian);
break;
default:
throw new UnsupportedOperationException();
......@@ -111,12 +133,17 @@ public class UpdateSchemeParallel implements UpdateSchemeOSM {
* @param pedestrian the pedestrian
* @param timeStepInSec the duration of the time step in seconds
*/
protected void updateParallelSeek(@NotNull final PedestrianOSM pedestrian, double timeStepInSec) {
pedestrian.setTimeCredit(pedestrian.getTimeCredit() + timeStepInSec);
protected void updateParallelSeek(@NotNull final PedestrianOSM pedestrian, final double currentTimeInSec, final double timeStepInSec) {
if (pedestrian.getTimeOfNextStep() == Pedestrian.INVALID_NEXT_EVENT_TIME) {
pedestrian.setTimeOfNextStep(currentTimeInSec);
return;
}
if (pedestrian.getTimeCredit() > pedestrian.getDurationNextStep()) {
if (pedestrian.getTimeOfNextStep() < currentTimeInSec) {
pedestrian.updateNextPosition();
movedPedestrians.add(pedestrian);
synchronized (movePedestrians) {
movePedestrians.add(pedestrian);
}
}
}
......@@ -127,12 +154,9 @@ public class UpdateSchemeParallel implements UpdateSchemeOSM {
*
* @param pedestrian the pedestrian
*/
private void updateParallelMove(@NotNull final PedestrianOSM pedestrian) {
if (movedPedestrians.contains(pedestrian)) {
pedestrian.setLastPosition(pedestrian.getPosition());
synchronized (topography) {
movePedestrian(topography, pedestrian, pedestrian.getPosition(), pedestrian.getNextPosition());
}
private void updateParallelMove(@NotNull final PedestrianOSM pedestrian, final double timeStepInSec) {
if (movePedestrians.contains(pedestrian)) {
osmBehaviorController.makeStep(pedestrian, topography, timeStepInSec);
}
}
......@@ -143,63 +167,43 @@ public class UpdateSchemeParallel implements UpdateSchemeOSM {
* @param pedestrian the pedestrian for which a rollback might be performed.
*/
protected void updateParallelConflicts(@NotNull final PedestrianOSM pedestrian) {
if (movedPedestrians.contains(pedestrian)) {
if (movePedestrians.contains(pedestrian)) {
pedestrian.refreshRelevantPedestrians();
List<Agent> others = getCollisionPedestrians(pedestrian);
boolean undoStep = false;
for (Agent ped : others) {
double creditOther = ((PedestrianOSM) ped).getTimeCredit();
double otherTimeOfNextEvent = ((PedestrianOSM) ped).getTimeOfNextStep();
double timeOfNextEvent = pedestrian.getTimeOfNextStep();
if (creditOther < pedestrian.getTimeCredit()) {
if (otherTimeOfNextEvent < timeOfNextEvent) {
undoStep = true;
break;
} else if (creditOther == pedestrian.getTimeCredit()
&& ped.getId() < pedestrian.getId()) {
} else if (otherTimeOfNextEvent == timeOfNextEvent && ped.getId() < pedestrian.getId()) {
undoStep = true;
break;
}
}
if (undoStep) {
synchronized (topography) {
movePedestrian(topography, pedestrian, pedestrian.getPosition(), pedestrian.getLastPosition());
if (!undoStep) {
synchronized (undoPedestrians) {
undoPedestrians.add(pedestrian);
}
}
}
}
/**
* Updates the timeCredit and the velocity of the pedestrian.
*
* @param pedestrian the pedestrian
* @param timeStepInSec the duration of the time step in seconds
*/
private void updateParallelSteps(@NotNull final PedestrianOSM pedestrian, double timeStepInSec) {
if (movedPedestrians.contains(pedestrian)) {
// did not want to make a step
if (pedestrian.getNextPosition().equals(pedestrian.getLastPosition())) {
pedestrian.setTimeCredit(0);
pedestrian.setVelocity(new Vector2D(0, 0));
}
// made a step
else if (!pedestrian.getPosition().equals(pedestrian.getLastPosition())) {
pedestrian.setTimeCredit(pedestrian.getTimeCredit() - pedestrian.getDurationNextStep());
// compute velocity by forward difference
pedestrian.setVelocity(new Vector2D(
pedestrian.getNextPosition().x - pedestrian.getLastPosition().x,
pedestrian.getNextPosition().y - pedestrian.getLastPosition().y)
.multiply(1.0 / timeStepInSec));
}
// wanted to make a step, but could not
else {
pedestrian.setVelocity(new Vector2D(0, 0));
protected void updateParallelSteps(@NotNull final PedestrianOSM pedestrian) {
if(movePedestrians.contains(pedestrian)) {
if(undoPedestrians.contains(pedestrian)) {
pedestrian.setTimeOfNextStep(pedestrian.getTimeOfNextStep() + pedestrian.getDurationNextStep());
} else {
osmBehaviorController.undoStep(pedestrian, topography);
}
}
}
/**
* Computes a {@link List<Agent>} of pedestrians overlapping / colliding with the pedestrian
* @param pedestrian the pedestrian
......
......@@ -12,10 +12,6 @@ import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
/**
* TODO: explain the concept of timeCredit!
* TODO: in the long term, replace timeCredit by eventTime (see event driven update)!
*/
public class UpdateSchemeSequential implements UpdateSchemeOSM {
private final Topography topography;
......@@ -53,19 +49,17 @@ public class UpdateSchemeSequential implements UpdateSchemeOSM {
}
if (mostImportantStimulus instanceof ElapsedTime) {
pedestrian.setTimeCredit(pedestrian.getTimeCredit() + timeStepInSec);
pedestrian.clearStrides();
if (pedestrian.getSelfCategory() == SelfCategory.TARGET_ORIENTED) {
useTimeCredit(pedestrian, timeStepInSec);
stepForward(pedestrian, currentTimeInSec, timeStepInSec);
} else if (pedestrian.getSelfCategory() == SelfCategory.COOPERATIVE) {
PedestrianOSM candidate = osmBehaviorController.findSwapCandidate(pedestrian, topography);
if(candidate != null) {
candidate.setTimeCredit(pedestrian.getTimeCredit() + timeStepInSec);
osmBehaviorController.swapPedestrians(pedestrian, candidate, topography);
// here we update not only pedestrian but also candidate, therefore candidate is already treated and will be skipped.
skipUdate.add(candidate);
} else {
useTimeCredit(pedestrian, timeStepInSec);
stepForward(pedestrian, currentTimeInSec, timeStepInSec);
}
}
} else if (mostImportantStimulus instanceof Wait || mostImportantStimulus instanceof WaitInArea) {
......@@ -77,8 +71,8 @@ public class UpdateSchemeSequential implements UpdateSchemeOSM {
}
}
private void useTimeCredit(@NotNull final PedestrianOSM pedestrian, final double timeStepInSec) {
while (pedestrian.getTimeCredit() > pedestrian.getDurationNextStep()) {
private void stepForward(@NotNull final PedestrianOSM pedestrian, final double simTimeInSec, final double timeStepInSec) {
while (pedestrian.getTimeOfNextStep() < simTimeInSec) {
pedestrian.updateNextPosition();
osmBehaviorController.makeStep(pedestrian, topography, timeStepInSec);
pedestrian.setTimeOfNextStep(pedestrian.getTimeOfNextStep() + pedestrian.getDurationNextStep());
......
......@@ -427,37 +427,6 @@ public class OSMBehaviorControllerTest {
assertEquals(expectedTimeOfNextStep, pedestrian2.getTimeOfNextStep(), ALLOWED_DOUBLE_TOLERANCE);
}
@Test
public void swapPedestriansHandlesOSMTimeCreditParametersProperly() {
createSameDirectionTopography();
double timeOfNextStepPed1 = 1;
double timeOfNextStepPed2 = 1.5;
pedestrian1.setTimeOfNextStep(timeOfNextStepPed1);
pedestrian2.setTimeOfNextStep(timeOfNextStepPed2);
double timeCreditInSecPed1 = 1;
double timeCreditInSecPed2 = 1.5;
pedestrian1.setTimeCredit(timeCreditInSecPed1);
pedestrian2.setTimeCredit(timeCreditInSecPed2);
double maxStepDuration = Math.max(pedestrian1.getDurationNextStep(), pedestrian2.getDurationNextStep());
double stepDurationPed1 = pedestrian1.getDurationNextStep();
OSMBehaviorController controllerUnderTest = new OSMBehaviorController();
controllerUnderTest.swapPedestrians(pedestrian1, pedestrian2, topography);
// For event-driven update scheme "timeOfNextStep" must be set properly.
double expectedTimeOfNextStep = timeOfNextStepPed1 + maxStepDuration;
assertEquals(expectedTimeOfNextStep, pedestrian1.getTimeOfNextStep(), ALLOWED_DOUBLE_TOLERANCE);
assertEquals(expectedTimeOfNextStep, pedestrian2.getTimeOfNextStep(), ALLOWED_DOUBLE_TOLERANCE);
// For sequential update scheme "timeCredit" must be set properly.
double expectedTimeCredit = timeCreditInSecPed1 - (stepDurationPed1 + maxStepDuration);
assertEquals(expectedTimeCredit, pedestrian1.getTimeCredit(), ALLOWED_DOUBLE_TOLERANCE);
assertEquals(expectedTimeCredit, pedestrian2.getTimeCredit(), ALLOWED_DOUBLE_TOLERANCE);
}
@Test
public void findSwapCandidateReturnsNullIfGivenPedestrianHasNotTarget() {
createOppositeDirectionVariation2Topography();
......@@ -652,21 +621,4 @@ public class OSMBehaviorControllerTest {
double expectedTimeOfNextStep = currentSimTimeInSec + timeOfNextStep;
assertEquals(expectedTimeOfNextStep, pedestrian1.getTimeOfNextStep(), ALLOWED_DOUBLE_TOLERANCE);
}
@Test
public void waitSetsTimeCreditToZeroForSequentialUpdateScheme() {
createSameDirectionTopography();
double timeCredit = 1.0;
pedestrian1.setTimeCredit(timeCredit);
assertEquals(timeCredit, pedestrian1.getTimeCredit(), ALLOWED_DOUBLE_TOLERANCE);
double currentSimTimeInSec = 1.0;
OSMBehaviorController controllerUnderTest = new OSMBehaviorController();
controllerUnderTest.wait(pedestrian1, currentSimTimeInSec);
double expectedTimeCredit = 0;
assertEquals(expectedTimeCredit, pedestrian1.getTimeCredit(), ALLOWED_DOUBLE_TOLERANCE);
}
}
\ No newline at end of file