Commit f66955de authored by Benedikt Zoennchen's avatar Benedikt Zoennchen

first dirty implementation of a parallel update scheme computing the next...

first dirty implementation of a parallel update scheme computing the next positions on the GPU via OpenCL.
parent 3caca386
package org.vadere.simulator.models.osm;
import org.jetbrains.annotations.NotNull;
import org.vadere.annotation.factories.models.ModelClass;
import org.vadere.simulator.control.factory.GroupSourceControllerFactory;
import org.vadere.simulator.control.factory.SingleSourceControllerFactory;
......@@ -19,16 +20,17 @@ import org.vadere.simulator.models.osm.optimization.StepCircleOptimizerEvolStrat
import org.vadere.simulator.models.osm.optimization.StepCircleOptimizerGradient;
import org.vadere.simulator.models.osm.optimization.StepCircleOptimizerNelderMead;
import org.vadere.simulator.models.osm.optimization.StepCircleOptimizerPowell;
import org.vadere.simulator.models.osm.updateScheme.ParallelWorkerOSM;
import org.vadere.simulator.models.osm.updateScheme.UpdateSchemeOSM;
import org.vadere.simulator.models.osm.updateScheme.UpdateSchemeOSM.CallMethod;
import org.vadere.simulator.models.potential.PotentialFieldModel;
import org.vadere.simulator.models.potential.fields.IPotentialFieldTarget;
import org.vadere.simulator.models.potential.fields.IPotentialFieldTargetGrid;
import org.vadere.simulator.models.potential.fields.PotentialFieldAgent;
import org.vadere.simulator.models.potential.fields.PotentialFieldObstacle;
import org.vadere.state.attributes.Attributes;
import org.vadere.state.attributes.models.AttributesFloorField;
import org.vadere.state.attributes.models.AttributesOSM;
import org.vadere.state.attributes.models.AttributesPotentialCompact;
import org.vadere.state.attributes.models.AttributesPotentialCompactSoftshell;
import org.vadere.state.attributes.scenario.AttributesAgent;
import org.vadere.state.scenario.DynamicElement;
import org.vadere.state.scenario.DynamicElementRemoveListener;
......@@ -37,12 +39,13 @@ import org.vadere.state.scenario.Topography;
import org.vadere.state.types.OptimizationType;
import org.vadere.state.types.UpdateType;
import org.vadere.util.geometry.shapes.VPoint;
import org.vadere.util.potential.CellGrid;
import org.vadere.util.potential.calculators.EikonalSolver;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;
import java.util.Optional;
import java.util.PriorityQueue;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
......@@ -77,7 +80,7 @@ public class OptimalStepsModel implements MainModel, PotentialFieldModel, Dynami
this.topography = topography;
this.random = random;
this.attributesPedestrian = attributesPedestrian;
this.updateSchemeOSM = UpdateSchemeOSM.create(attributesOSM.getUpdateType(), topography, random);
this.updateSchemeOSM = createUpdateScheme(modelAttributesList, topography, attributesOSM);
this.topography.addElementAddedListener(Pedestrian.class, updateSchemeOSM);
this.topography.addElementRemovedListener(Pedestrian.class, updateSchemeOSM);
......@@ -131,6 +134,50 @@ public class OptimalStepsModel implements MainModel, PotentialFieldModel, Dynami
models.add(this);
}
// Dirty quick implementation to test it! TODO: refactoring!
private UpdateSchemeOSM createUpdateScheme(
@NotNull final List<Attributes> attributesList,
@NotNull final Topography topography,
@NotNull final AttributesOSM attributesOSM) {
switch (attributesOSM.getUpdateType()) {
case PARALLEL_OPEN_CL: {
return UpdateSchemeOSM.createOpenCLUpdateScheme(
topography,
attributesOSM,
Model.findAttributes(attributesList, AttributesFloorField.class),
new AttributesPotentialCompact().getPedPotentialWidth(),
new EikonalSolver() {
CellGrid cellGrid = ((IPotentialFieldTargetGrid)potentialFieldTarget).getCellGrids().get(1);
@Override
public void initialize() {}
@Override
public CellGrid getPotentialField() {
return cellGrid;
}
},
new EikonalSolver() {
CellGrid cellGrid = topography.getDistanceFunctionApproximation(
Model.findAttributes(attributesList, AttributesFloorField.class).getPotentialFieldResolution()
);
@Override
public void initialize() {}
@Override
public CellGrid getPotentialField() {
return cellGrid;
}
}
);
}
default: return UpdateSchemeOSM.create(attributesOSM.getUpdateType(), topography, random);
}
}
private StepCircleOptimizer createStepCircleOptimizer(
AttributesOSM attributesOSM, Random random, Topography topography,
IPotentialFieldTargetGrid potentialFieldTarget) {
......
package org.vadere.simulator.models.osm.opencl;
import com.sun.tools.internal.xjc.model.Model;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.jetbrains.annotations.NotNull;
......@@ -215,7 +217,7 @@ public class CLOptimalStepsModel {
return getPotentialFieldWidth() * getPotentialFieldHeight();
}
private FloatBuffer generatePotentialFieldApproximation(@NotNull EikonalSolver eikonalSolver) {
private FloatBuffer generatePotentialFieldApproximation(@NotNull final EikonalSolver eikonalSolver) {
FloatBuffer floatBuffer = MemoryUtil.memAllocFloat(getPotentialFieldSize());
int index = 0;
......
package org.vadere.simulator.models.osm.updateScheme;
import org.vadere.simulator.models.osm.PedestrianOSM;
import org.vadere.simulator.models.osm.updateScheme.UpdateSchemeOSM.CallMethod;
public class ParallelWorkerOSM implements Runnable {
private final PedestrianOSM ped;
private final CallMethod callMethod;
private final double timeStepInSec;
public ParallelWorkerOSM(CallMethod callMethod, PedestrianOSM ped,
double timeStepInSec) {
this.ped = ped;
this.callMethod = callMethod;
this.timeStepInSec = timeStepInSec;
}
@Override
public void run() {
//ped.update(timeStepInSec, -1, callMethod);
}
}
package org.vadere.simulator.models.osm.updateScheme;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.jetbrains.annotations.NotNull;
import org.vadere.simulator.models.osm.PedestrianOSM;
import org.vadere.simulator.models.osm.opencl.CLOptimalStepsModel;
import org.vadere.state.scenario.Pedestrian;
import org.vadere.state.scenario.Topography;
import org.vadere.util.io.ListUtils;
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
*/
public class UpdateSchemeCLParellel extends UpdateSchemeParallel {
public UpdateSchemeCLParellel(@NotNull final Topography pedestrian) {
super(pedestrian);
private CLOptimalStepsModel clOptimalStepsModel;
private Logger logger = LogManager.getLogger(UpdateSchemeCLParellel.class);
public UpdateSchemeCLParellel(@NotNull final Topography topography, @NotNull final CLOptimalStepsModel clOptimalStepsModel) {
super(topography);
this.clOptimalStepsModel = clOptimalStepsModel;
}
/*
pedestrian.setTimeCredit(pedestrian.getTimeCredit() + timeStepInSec);
pedestrian.setDurationNextStep(pedestrian.getStepSize() / pedestrian.getDesiredSpeed());
if (pedestrian.getTimeCredit() > pedestrian.getDurationNextStep()) {
pedestrian.updateNextPosition();
movedPedestrians.add(pedestrian);
}
*/
@Override
public void update(double timeStepInSec, double currentTimeInSec) {
try {
movedPedestrians.clear();
List<PedestrianOSM> pedestrianOSMList = ListUtils.select(topography.getElements(Pedestrian.class), PedestrianOSM.class);
// CallMethod.SEEK runs on the GPU
List<CLOptimalStepsModel.PedestrianOpenCL> pedestrians = new ArrayList<>();
for(int i = 0; i < pedestrianOSMList.size(); i++) {
CLOptimalStepsModel.PedestrianOpenCL pedestrian = new CLOptimalStepsModel.PedestrianOpenCL(
pedestrianOSMList.get(i).getPosition(),
(float)pedestrianOSMList.get(i).getStepSize());
pedestrians.add(pedestrian);
}
List<CLOptimalStepsModel.PedestrianOpenCL> result = clOptimalStepsModel.getNextSteps(pedestrians);
for(int i = 0; i < pedestrians.size(); i++) {
logger.info("not equals for index = " + i + ": " + result.get(i).position + " -> " + result.get(i).newPosition);
PedestrianOSM pedestrian = pedestrianOSMList.get(i);
pedestrian.setDurationNextStep(pedestrian.getStepSize() / pedestrian.getDesiredSpeed());
if (pedestrian.getTimeCredit() > pedestrian.getDurationNextStep()) {
pedestrian.setNextPosition(result.get(i).newPosition);
movedPedestrians.add(pedestrian);
}
}
// these call methods run on the CPU
CallMethod[] callMethods = {CallMethod.MOVE, CallMethod.CONFLICTS, CallMethod.STEPS};
List<Future<?>> futures;
for (CallMethod callMethod : callMethods) {
futures = new LinkedList<>();
for (final PedestrianOSM pedestrian : pedestrianOSMList) {
Runnable worker = () -> update(pedestrian, timeStepInSec, currentTimeInSec, callMethod);
futures.add(executorService.submit(worker));
}
collectFutures(futures);
}
} catch (OpenCLException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
}
......@@ -2,11 +2,18 @@ package org.vadere.simulator.models.osm.updateScheme;
import org.jetbrains.annotations.NotNull;
import org.vadere.simulator.models.osm.opencl.CLOptimalStepsModel;
import org.vadere.state.attributes.models.AttributesFloorField;
import org.vadere.state.attributes.models.AttributesOSM;
import org.vadere.state.attributes.scenario.AttributesAgent;
import org.vadere.state.scenario.DynamicElementAddListener;
import org.vadere.state.scenario.DynamicElementRemoveListener;
import org.vadere.state.scenario.Pedestrian;
import org.vadere.state.scenario.Topography;
import org.vadere.state.types.UpdateType;
import org.vadere.util.geometry.shapes.VRectangle;
import org.vadere.util.opencl.OpenCLException;
import org.vadere.util.potential.calculators.EikonalSolver;
import java.util.Random;
......@@ -27,4 +34,32 @@ public interface UpdateSchemeOSM extends DynamicElementRemoveListener<Pedestrian
default: throw new IllegalArgumentException(updateType + " is not supported.");
}
}
static UpdateSchemeOSM createOpenCLUpdateScheme(
@NotNull final Topography topography,
@NotNull final AttributesOSM attributesOSM,
@NotNull final AttributesFloorField attributesFloorField,
@NotNull final double pedestrianPotentialWidth,
@NotNull final EikonalSolver targetEikonalSolver,
@NotNull final EikonalSolver distanceEikonalSolver) {
try {
CLOptimalStepsModel clOptimalStepsModel = new CLOptimalStepsModel(
attributesOSM,
attributesFloorField,
topography.getPedestrianDynamicElements().getElements().size(),
new VRectangle(topography.getBounds()),
pedestrianPotentialWidth, // max step length + function width
targetEikonalSolver,
distanceEikonalSolver);
return new UpdateSchemeCLParellel(topography, clOptimalStepsModel);
} catch (OpenCLException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
}
......@@ -19,13 +19,13 @@ import org.vadere.util.io.ListUtils;
public class UpdateSchemeParallel implements UpdateSchemeOSM {
private ExecutorService executorService;
private final Topography topography;
private Set<Pedestrian> movedPedestrians;
protected final ExecutorService executorService;
protected final Topography topography;
protected final Set<Pedestrian> movedPedestrians;
public UpdateSchemeParallel(@NotNull final Topography topography) {
this.topography = topography;
this.executorService = Executors.newSingleThreadExecutor();
this.executorService = Executors.newFixedThreadPool(8);
this.movedPedestrians = new HashSet<>();
}
......@@ -45,7 +45,7 @@ public class UpdateSchemeParallel implements UpdateSchemeOSM {
}
}
private void collectFutures(final List<Future<?>> futures) {
protected void collectFutures(final List<Future<?>> futures) {
try {
for (Future<?> future : futures) {
future.get();
......@@ -59,7 +59,7 @@ public class UpdateSchemeParallel implements UpdateSchemeOSM {
}
}
private void update(@NotNull final PedestrianOSM pedestrian, final double timeStepInSec, double currentTimeInSec, CallMethod callMethod) {
protected void update(@NotNull final PedestrianOSM pedestrian, final double timeStepInSec, double currentTimeInSec, CallMethod callMethod) {
pedestrian.clearStrides();
switch (callMethod) {
case SEEK:
......
......@@ -24,6 +24,9 @@ import org.vadere.state.attributes.scenario.AttributesTopography;
import org.vadere.util.geometry.LinkedCellsGrid;
import org.vadere.util.geometry.shapes.VPoint;
import org.vadere.util.geometry.shapes.VShape;
import org.vadere.util.potential.CellGrid;
import org.vadere.util.potential.CellState;
import org.vadere.util.potential.PathFindingTag;
@JsonIgnoreProperties(value = {"allOtherAttributes", "obstacleDistanceFunction"})
public class Topography {
......@@ -152,6 +155,18 @@ public class Topography {
this.obstacleDistanceFunction = obstacleDistanceFunction;
}
public CellGrid getDistanceFunctionApproximation(final double cellSize) {
CellGrid cellGrid = new CellGrid(getBounds().width, getBounds().height, cellSize, new CellState());
for(int row = 0; row < cellGrid.getNumPointsY(); row++){
for(int col = 0; col < cellGrid.getNumPointsX(); col++){
cellGrid.setValue(col, row, new CellState(
distanceToObstacle(cellGrid.pointToCoord(col, row).add(new VPoint(getBounds().getMinX(), getBounds().getMinY()))),
PathFindingTag.Reachable));
}
}
return cellGrid;
}
public boolean containsTarget(final Predicate<Target> targetPredicate) {
return getTargets().stream().anyMatch(targetPredicate);
}
......
package org.vadere.state.types;
public enum UpdateType {
SEQUENTIAL, EVENT_DRIVEN, PARALLEL, SHUFFLE
SEQUENTIAL, EVENT_DRIVEN, PARALLEL, SHUFFLE, PARALLEL_OPEN_CL
}
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