Commit 7b6bede4 authored by Stefan Schuhbaeck's avatar Stefan Schuhbaeck
Browse files

Merge branch 'add_traci_cmds' into 'master'

Add traci cmds

See merge request !111
parents b58ccef5 78e0aaa4
Pipeline #205918 passed with stages
in 125 minutes and 26 seconds
......@@ -2,6 +2,7 @@ package org.vadere.manager;
import org.vadere.gui.onlinevisualization.OnlineVisualization;
import org.vadere.manager.traci.commandHandler.StateAccessHandler;
import org.vadere.manager.traci.compound.object.SimulationCfg;
import org.vadere.simulator.control.simulation.SimulationState;
import org.vadere.simulator.entrypoints.ScenarioFactory;
import org.vadere.simulator.projects.RunnableFinishedListener;
......@@ -13,6 +14,7 @@ import org.vadere.util.logging.Logger;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
......@@ -35,17 +37,19 @@ public class RemoteManager implements RunnableFinishedListener {
private Thread currentSimulationThread;
private boolean simulationFinished;
private boolean clientCloseCommandReceived;
private Path baseDir;
private Path defaultOutputdir; // defined by command line parameter. May be overwritten by simCfg
private boolean guiSupport;
private SimulationCfg simCfg; // received from traci client.
private List<Subscription> subscriptions;
public RemoteManager(Path baseDir, boolean guiSupport) {
this.baseDir = baseDir;
public RemoteManager(Path defaultOutputdir, boolean guiSupport) {
this.defaultOutputdir = defaultOutputdir;
this.guiSupport = guiSupport;
this.subscriptions = new ArrayList<>();
this.clientCloseCommandReceived = false;
this.simCfg = null;
}
public void loadScenario(String scenarioString, Map<String, ByteArrayInputStream> cacheData) {
......@@ -54,23 +58,35 @@ public class RemoteManager implements RunnableFinishedListener {
ScenarioCache scenarioCache;
Path scenarioPath;
Path outputDir;
if (simCfg != null) {
outputDir = Paths.get(simCfg.outputPath());
logger.infof("received output directory from traci client '%s'", simCfg.outputPath());
} else {
outputDir = defaultOutputdir;
}
try {
scenario = ScenarioFactory.createScenarioWithScenarioJson(scenarioString);
scenarioPath = baseDir.resolve(IOUtils.SCENARIO_DIR).resolve(scenario.getName() + IOUtils.SCENARIO_FILE_EXTENSION);
scenarioPath = defaultOutputdir.resolve(IOUtils.SCENARIO_DIR).resolve(scenario.getName()
+ IOUtils.SCENARIO_FILE_EXTENSION);
scenarioCache = buildScenarioCache(scenario, cacheData);
} catch (IOException e) {
throw new TraCIException("Cannot create Scenario from given file.");
}
currentSimulationRun = new RemoteScenarioRun(scenario, baseDir, this, scenarioPath, scenarioCache);
if (simCfg != null) {
scenario.getAttributesSimulation().setFixedSeed(simCfg.getSeed());
scenario.getAttributesSimulation().setUseFixedSeed(true);
logger.infof("received seed from traci client '%s'", Long.toString(simCfg.getSeed()));
}
currentSimulationRun = new RemoteScenarioRun(scenario, outputDir, this, scenarioPath, scenarioCache);
}
public void loadScenario(String scenarioString) {
loadScenario(scenarioString, null);
}
private ScenarioCache buildScenarioCache(final Scenario scenario, Map<String, ByteArrayInputStream> cacheData) {
ScenarioCache scenarioCache = ScenarioCache.load(scenario, baseDir);
ScenarioCache scenarioCache = ScenarioCache.load(scenario, defaultOutputdir);
if (scenarioCache.isEmpty()) {
if (cacheData != null) {
logger.warnf("received cache data but given Scenario has cache deactivated. Received cache will be ignored");
......@@ -165,4 +181,12 @@ public class RemoteManager implements RunnableFinishedListener {
logger.infof("Start Scenario %s with remote control...", currentSimulationRun.getScenario().getName());
currentSimulationThread.start();
}
public SimulationCfg getSimCfg() {
return simCfg;
}
public void setSimCfg(SimulationCfg simCfg) {
this.simCfg = simCfg;
}
}
......@@ -463,6 +463,11 @@ public class TestClient extends org.vadere.manager.client.AbstractTestClient imp
System.out.println(res.toString());
}
@Override
public void simulationapi_setSimConfig(String[] args) throws IOException {
System.out.println("not implemented");
}
// polygonapi
@Override
public void polygonapi_getTopographyBounds(String[] args) throws IOException {
......
......@@ -13,6 +13,7 @@ public enum TraCIDataType {
DOUBLE(0x0B, 8, true),
STRING(0x0C, -1, true),
STRING_LIST(0x0E, -1, true),
COMPOUND_OBJECT(0x0F, -1, true),
POS_2D(0x01, 17, false),
POS_2D_LIST(0x10, -1, true),
POS_3D(0x03, 25, false),
......
......@@ -3,6 +3,7 @@ package org.vadere.manager.traci.commandHandler;
import org.vadere.annotation.traci.client.TraCIApi;
import org.vadere.manager.RemoteManager;
import org.vadere.manager.TraCICommandCreationException;
import org.vadere.manager.TraCIException;
import org.vadere.manager.traci.TraCICmd;
import org.vadere.manager.traci.TraCIDataType;
import org.vadere.manager.traci.commandHandler.annotation.SimulationHandler;
......@@ -12,11 +13,14 @@ import org.vadere.manager.traci.commands.TraCICommand;
import org.vadere.manager.traci.commands.TraCIGetCommand;
import org.vadere.manager.traci.commands.TraCISetCommand;
import org.vadere.manager.traci.commands.get.TraCIGetCacheHashCommand;
import org.vadere.manager.traci.compound.CompoundObject;
import org.vadere.manager.traci.compound.object.SimulationCfg;
import org.vadere.manager.traci.response.TraCIGetResponse;
import org.vadere.simulator.entrypoints.ScenarioFactory;
import org.vadere.simulator.projects.Scenario;
import org.vadere.simulator.utils.cache.ScenarioCache;
import org.vadere.util.geometry.shapes.VPoint;
import org.vadere.util.logging.Logger;
import java.awt.geom.Rectangle2D;
import java.io.IOException;
......@@ -39,6 +43,7 @@ import java.util.ArrayList;
)
public class SimulationCommandHandler extends CommandHandler<SimulationVar> {
private static Logger logger = Logger.getLogger(SimulationCommandHandler.class);
public static SimulationCommandHandler instance;
static {
......@@ -92,7 +97,8 @@ public class SimulationCommandHandler extends CommandHandler<SimulationVar> {
return cmd;
}
@SimulationHandler(cmd = TraCICmd.GET_SIMULATION_VALUE, var = SimulationVar.CURR_SIM_TIME, name = "getTime", ignoreElementId = true)
@SimulationHandler(cmd = TraCICmd.GET_SIMULATION_VALUE, var = SimulationVar.CURR_SIM_TIME,
name = "getTime", ignoreElementId = true)
public TraCICommand process_getSimTime(TraCIGetCommand cmd, RemoteManager remoteManager, SimulationVar traCIVar) {
remoteManager.accessState((manager, state) -> {
......@@ -104,7 +110,23 @@ public class SimulationCommandHandler extends CommandHandler<SimulationVar> {
return cmd;
}
@SimulationHandler(cmd = TraCICmd.GET_SIMULATION_VALUE, var = SimulationVar.CACHE_HASH, name = "getHash", dataTypeStr = "String", ignoreElementId = true)
@SimulationHandler(cmd = TraCICmd.SET_SIMULATION_STATE, var = SimulationVar.SIM_CONFIG,
name = "setSimConfig", ignoreElementId = true)
public TraCICommand process_setSimConfig(TraCISetCommand cmd, RemoteManager remoteManager) {
try {
SimulationCfg cfg = new SimulationCfg((CompoundObject) cmd.getVariableValue());
remoteManager.setSimCfg(cfg);
cmd.setOK();
} catch (TraCIException ex) {
logger.errorf("cannot parse setSimConfig object. Err: %s", ex.getMessage());
cmd.setErr(String.format("cannot parse setSimConfig object. Err: %s", ex.getMessage()));
}
return cmd;
}
@SimulationHandler(cmd = TraCICmd.GET_SIMULATION_VALUE, var = SimulationVar.CACHE_HASH,
name = "getHash", dataTypeStr = "String", ignoreElementId = true)
public TraCICommand process_getCacheHash(TraCIGetCommand rawCmd, RemoteManager remoteManager) {
try {
......@@ -185,7 +207,8 @@ public class SimulationCommandHandler extends CommandHandler<SimulationVar> {
TraCISetCommand cmd = (TraCISetCommand) rawCmd;
SimulationVar var = SimulationVar.fromId(cmd.getVariableId());
switch (var) {
case CACHE_HASH:
case SIM_CONFIG:
return process_setSimConfig(cmd, remoteManager);
default:
return process_NotImplemented(cmd, remoteManager);
}
......
......@@ -19,6 +19,7 @@ public enum SimulationVar {
//
NETWORK_BOUNDING_BOX_2D(0x7c, TraCIDataType.POLYGON),
CACHE_HASH(0x7d, TraCIDataType.STRING),
SIM_CONFIG(0x7e, TraCIDataType.COMPOUND_OBJECT),
;
public int id;
......
package org.vadere.manager.traci.compound;
import org.apache.commons.lang3.tuple.Pair;
import org.vadere.manager.TraCIException;
import org.vadere.manager.traci.TraCIDataType;
import java.util.Iterator;
/**
* CompoundObject implementation based on TraCI as described in https://sumo.dlr.de/docs/TraCI/Protocol.html#atomar_types
*
* This implementation consist of two equally long arrays {@link #type} and {@link #data}. The
* {@link #type} array saves Type of the objects at the same index in {@link #data}.
*
* At time of creation it must be stated how many objects will be tide together. See @{@link
* CompoundObjectBuilder} for usage of Constructor and the {@link #add(int, Object)} method.
*/
public class CompoundObject {
private TraCIDataType[] type;
private Object[] data;
private int cur;
public CompoundObject(int noElements) {
this.type = new TraCIDataType[noElements];
this.data = new Object[noElements];
this.cur = 0;
}
public String types() {
StringBuilder sb = new StringBuilder();
sb.append("[");
for (TraCIDataType i : this.type) {
sb.append(i.name()).append(", ");
}
sb.delete(sb.length() - 2, sb.length());
sb.append("]");
return sb.toString();
}
public int size() {
return data.length;
}
public CompoundObject add(int type, Object data) {
return add(TraCIDataType.fromId(type), data);
}
public CompoundObject add(TraCIDataType type, Object data) {
if (cur > this.data.length)
throw new TraCIException("CompoundObject already full. Received " + types());
this.type[cur] = type;
this.data[cur] = data;
cur++;
return this;
}
public boolean hasIndex(int index) {
return hasIndex(index, null);
}
public boolean hasIndex(int index, TraCIDataType type) {
if (index >= 0 && index < this.data.length) {
if (type != null) {
return this.type[index].equals(type);
}
return true;
}
return false;
}
public Object getData(int index, TraCIDataType type) {
if (index > this.data.length)
throw new TraCIException("Cannot access data with index %d", index);
if (!this.type[index].equals(type))
throw new TraCIException("Type mismatch of CompoundObject element %s != %s at index %d",
this.type[index].name(), type.name(), index);
return this.data[index];
}
public Object getData(int index) {
if (index > this.data.length)
throw new TraCIException("Cannot access data with index %d", index);
return this.data[index];
}
public Iterator<Pair<TraCIDataType, Object>> itemIterator() {
return new Iter(this, null);
}
public Iterator<Pair<TraCIDataType, Object>> itemIterator(TraCIDataType typeAssertion) {
return new Iter(this, typeAssertion);
}
private class Iter implements Iterator<Pair<TraCIDataType, Object>> {
private final CompoundObject compoundObject;
private final TraCIDataType typeAssertion;
private int curr;
Iter(CompoundObject compoundObject, TraCIDataType typeAssertion) {
this.compoundObject = compoundObject;
this.typeAssertion = typeAssertion;
this.curr = 0;
}
@Override
public boolean hasNext() {
return curr < compoundObject.size();
}
@Override
public Pair<TraCIDataType, Object> next() {
Pair<TraCIDataType, Object> p = Pair.of(compoundObject.type[curr], compoundObject.data[curr]);
if (!p.getLeft().equals(this.typeAssertion)) {
throw new TraCIException("Type mismatch in CompoundObject. Expected '%s' but found '%s'",
this.typeAssertion.name(), p.getLeft().name());
}
curr++;
return p;
}
}
}
package org.vadere.manager.traci.compound;
import org.vadere.manager.TraCIException;
import org.vadere.manager.traci.TraCIDataType;
import java.util.LinkedList;
/**
* Builder class to create any combination atomar data types combined in a @{@link CompoundObject}.
* See static methods on how the builder is used. Ensure that the number of {@link
* #add(TraCIDataType)} calls is equal to the number of arguments to the {@link #build(Object...)}.
*/
public class CompoundObjectBuilder {
private LinkedList<TraCIDataType> types;
public CompoundObjectBuilder() {
this.types = new LinkedList<>();
}
public CompoundObjectBuilder rest() {
types.clear();
return this;
}
public CompoundObjectBuilder add(TraCIDataType type) {
types.add(type);
return this;
}
public CompoundObjectBuilder add(TraCIDataType type, int count) {
for (int i = 0; i < count; i++) {
types.add(type);
}
return this;
}
public CompoundObject build(Object... data) {
CompoundObject obj = new CompoundObject(data.length);
if (types.size() == data.length) {
int idx = 0;
for (TraCIDataType type : types) {
obj.add(type, data[idx]);
idx++;
}
} else {
throw new TraCIException("CompoundObjectBuilder error. Number of Types does not match" +
" received number of data items");
}
return obj;
}
static public CompoundObjectBuilder builder() {
return new CompoundObjectBuilder();
}
static public CompoundObject json(String json) {
return CompoundObjectBuilder.builder()
.rest()
.add(TraCIDataType.STRING)
.build(json);
}
}
package org.vadere.manager.traci.compound.object;
import org.vadere.manager.TraCIException;
import org.vadere.manager.traci.TraCIDataType;
import org.vadere.manager.traci.compound.CompoundObject;
import org.vadere.manager.traci.compound.CompoundObjectBuilder;
import java.util.Objects;
/**
* Configuration options received from TraCI client.
*
* Used to seed Random object and redirect output to a client defined location.
*/
public class SimulationCfg {
private String configName;
private String experiment;
private String dateTime;
private String resultRootDir;
private String iterationVariables;
private String repetition;
private String outputScalarFile;
private String outputVecFile;
private long seed;
public static CompoundObject asCompoundObject(String configName,
String experiment,
String dateTime,
String resultRootDir,
String iterationVariables,
String repetition,
String outputScalarFile,
String outputVecFile,
long seed) {
return CompoundObjectBuilder.builder()
.rest()
.add(TraCIDataType.STRING, 8)
.add(TraCIDataType.INTEGER)
.build(configName,
experiment,
dateTime,
resultRootDir,
iterationVariables,
repetition,
outputScalarFile,
outputVecFile,
seed);
}
public SimulationCfg(CompoundObject obj) {
if (obj.size() != 9) {
throw new TraCIException("Expected at least 9 elements");
}
configName = (String) obj.getData(0, TraCIDataType.STRING);
experiment = (String) obj.getData(1, TraCIDataType.STRING);
dateTime = (String) obj.getData(2, TraCIDataType.STRING);
resultRootDir = (String) obj.getData(3, TraCIDataType.STRING);
iterationVariables = (String) obj.getData(4, TraCIDataType.STRING);
repetition = (String) obj.getData(5, TraCIDataType.STRING);
outputScalarFile = (String) obj.getData(6, TraCIDataType.STRING);
outputVecFile = (String) obj.getData(7, TraCIDataType.STRING);
seed = Long.valueOf((int) obj.getData(8, TraCIDataType.INTEGER));
}
public String outputPath() {
if (outputVecFile.endsWith(".vec")) {
return outputVecFile.substring(0, outputVecFile.length() - 4);
}
if (outputScalarFile.endsWith(".sca")) {
return outputScalarFile.substring(0, outputScalarFile.length() - 4);
}
return String.format("%s/%s/%s/%s_vars_%s_rep_%s",
resultRootDir,
configName,
experiment,
dateTime,
iterationVariables,
repetition
);
}
public String getConfigName() {
return configName;
}
public void setConfigName(String configName) {
this.configName = configName;
}
public String getExperiment() {
return experiment;
}
public void setExperiment(String experiment) {
this.experiment = experiment;
}
public String getDateTime() {
return dateTime;
}
public void setDateTime(String dateTime) {
this.dateTime = dateTime;
}
public String getResultRootDir() {
return resultRootDir;
}
public void setResultRootDir(String resultRootDir) {
this.resultRootDir = resultRootDir;
}
public String getIterationVariables() {
return iterationVariables;
}
public void setIterationVariables(String iterationVariables) {
this.iterationVariables = iterationVariables;
}
public String getRepetition() {
return repetition;
}
public void setRepetition(String repetition) {
this.repetition = repetition;
}
public String getOutputScalarFile() {
return outputScalarFile;
}
public void setOutputScalarFile(String outputScalarFile) {
this.outputScalarFile = outputScalarFile;
}
public String getOutputVecFile() {
return outputVecFile;
}
public void setOutputVecFile(String outputVecFile) {
this.outputVecFile = outputVecFile;
}
public long getSeed() {
return seed;
}
public void setSeed(long seed) {
this.seed = seed;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
SimulationCfg that = (SimulationCfg) o;
return seed == that.seed &&
configName.equals(that.configName) &&
experiment.equals(that.experiment) &&
dateTime.equals(that.dateTime) &&
resultRootDir.equals(that.resultRootDir) &&
iterationVariables.equals(that.iterationVariables) &&
repetition.equals(that.repetition) &&
outputScalarFile.equals(that.outputScalarFile) &&
outputVecFile.equals(that.outputVecFile);
}
@Override
public int hashCode() {
return Objects.hash(configName, experiment, dateTime, resultRootDir, iterationVariables, repetition, outputScalarFile, outputVecFile, seed);
}
@Override
public String toString() {
return "SimulationCfg{" +
"configName='" + configName + '\'' +
", experiment='" + experiment + '\'' +
", dateTime='" + dateTime + '\'' +
", resultRootDir='" + resultRootDir + '\'' +