Currently job artifacts in CI/CD pipelines on LRZ GitLab never expire. Starting from Wed 26.1.2022 the default expiration time will be 30 days (GitLab default). Currently existing artifacts in already completed jobs will not be affected by the change. The latest artifacts for all jobs in the latest successful pipelines will be kept. More information: https://gitlab.lrz.de/help/user/admin_area/settings/continuous_integration.html#default-artifacts-expiration

Commit 905a8f4a authored by Jakob Schöttl's avatar Jakob Schöttl
Browse files

Merge branch 'sealable' into develop

parents 55db5412 e0689ea2
......@@ -6,7 +6,6 @@ import java.nio.file.Paths;
import java.util.Locale;
import org.apache.log4j.Logger;
import org.vadere.simulator.projects.ScenarioRunLocked;
import org.vadere.simulator.projects.ScenarioRunManager;
import org.vadere.util.io.IOUtils;
......@@ -70,19 +69,9 @@ public class VadereConsole {
logger.info(String.format("Running VADERE on %s...", scenarioFilePath));
try {
if (projectDirectory == null) {
ScenarioRunLocked vadereJava = VadereFactory.createVadereWithFiles(Paths.get(outputFile).toString(),
scenarioFilePath, vadereName);
vadereJava.setWaitOnLockData(lockDirectory, timeStepFile, outputAll);
vadereJava.run();
} else {
ScenarioRunManager vadereJava = VadereFactory.createVadereWithProjectDirectory(projectDirectory,
vadereName + IOUtils.SCENARIO_FILE_EXTENSION, vadereName);
vadereJava.run();
}
ScenarioRunManager vadereJava = VadereFactory.createVadereWithProjectDirectory(projectDirectory,
vadereName + IOUtils.SCENARIO_FILE_EXTENSION, vadereName);
vadereJava.run();
} catch (IOException e) {
logger.error(e);
}
......
......@@ -2,7 +2,6 @@ package org.vadere.simulator.entrypoints;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.vadere.simulator.projects.ScenarioRunLocked;
import org.vadere.simulator.projects.ScenarioRunManager;
import org.vadere.simulator.projects.io.IOVadere;
import org.vadere.util.io.IOUtils;
......@@ -14,36 +13,12 @@ import java.nio.file.Paths;
/**
* The VadereFactory create new Vadere-Scenario objects.
*
*
*/
public class VadereFactory {
private static Logger logger = LogManager.getLogger(VadereFactory.class);
// Factory-Methods
/**
* Create a new Vadere object with the given file paths to output and scenario.
*
* @param outputFile path to the output file
* @param scenarioFilePath path to the scenario file
* @param name name of the vadere object
* @return a new Vadere object
* @throws IOException
*/
public static ScenarioRunLocked createVadereWithFiles(final String outputFile, final String scenarioFilePath,
final String name) throws IOException {
// TODO [priority=high] [task=rewrite] this class has a legacy name and is not implemented
/*
* String json = IOUtils.readTextFile(scenarioFilePath);
* ScenarioStore store = IOVadere.scenarioStoreFromJson(json);
* ScenarioRunLocked v = new ScenarioRunLocked(name, store.topography, store);
* v.setOutputPaths(Paths.get(outputFile), Paths.get(outputFile).getParent());
*/
return null; // v;
}
/**
* Create a new Vadere with the specified name based on the path to the directory of the project
* and the filename of the scenario of the Vadere.
......
package org.vadere.simulator.projects;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Random;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.vadere.simulator.control.Simulation;
import org.vadere.simulator.models.MainModelBuilder;
import org.vadere.state.attributes.scenario.AttributesAgent;
import org.vadere.state.scenario.Pedestrian;
import org.vadere.state.scenario.Topography;
import org.vadere.util.geometry.Vector2D;
import org.vadere.util.geometry.shapes.VPoint;
import org.vadere.util.io.filewatcher.LockFileHandler;
import au.com.bytecode.opencsv.CSVReader;
/**
* Can be used to start Vadere in [lock] mode.
* It will search for a lock file and starts running after it is removed.
*
*
*/
public class ScenarioRunLocked extends ScenarioRunManager {
private static Logger logger = LogManager.getLogger(ScenarioRunLocked.class);
private LockFileHandler lockFileHandler = null;
private String timeStepFile;
private String lockDirectory;
public ScenarioRunLocked(String name, ScenarioStore store) {
super(name, store);
this.lockDirectory = null;
}
@Override
public void run() {
doBeforeSimulation();
handleLock(Paths.get(this.lockDirectory));
}
/**
* Checks the given directory on lock files.
* If a lock file is present, the simulation pauses after reaching the specified finish time.
* When the lock gets released, the simulation is resumed with a new finish time.
*
* @param lockDirectory
*/
private void handleLock(Path lockDirectory) {
logger.info("Lock file monitoring started.");
File folder = new File(lockDirectory.toString());
if (!folder.exists()) {
// Test to see if monitored folder exists
throw new RuntimeException("Directory not found: " + lockDirectory);
}
final ScenarioRunManager thisVadere = this;
while (true) {
// TODO [priority=medium] [task=refactoring] improve error handling!
try {
lockFileHandler.waitForLockDelete();
Thread.sleep(100);
} catch (IOException e) {
logger.error(e);
System.exit(0);
} catch (InterruptedException e) {
logger.error(e);
}
try {
// "file" is the reference to the removed file
logger.info("Lock file removed.");
logger.info(String.format("Resuming '%s'...", thisVadere.getName()));
double currentTime = 0;
if (simulation == null) {
MainModelBuilder modelBuilder = new MainModelBuilder(scenarioStore);
modelBuilder.createModelAndRandom();
simulation = new Simulation(modelBuilder.getModel(), currentTime, getName(),
scenarioStore, passiveCallbacks, modelBuilder.getRandom(), thisVadere.processorManager);
} else {
currentTime = simulation.getCurrentTime();
// restart timer of the simulation
simulation.setStartTimeInSec(currentTime);
}
logger.info("Current time: " + currentTime);
try {
if (!Files.exists(Paths.get(timeStepFile))) {
Files.createFile(Paths.get(timeStepFile));
}
scenarioStore.topography = prepareTopographyWithTSF(scenarioStore.topography);
} catch (IOException e) {
logger.error(e);
}
try {
prepareLockOutput(simulation);
} catch (FileNotFoundException e) {
logger.error(e);
}
simulation.run();
scenarioStore.topography.getInitialElements(Pedestrian.class).clear(); // so that they are created only once
doAfterSimulation();
logger.info(String.format("Finished '%s'.", thisVadere.getName()));
} catch (ClassNotFoundException | InstantiationException
| IllegalAccessException e) {
e.printStackTrace();
}
try {
lockFileHandler.writeLock();
} catch (IOException e) {
logger.error(e);
System.exit(0);
}
}
}
public void setWaitOnLockData(String lockDirectory, String timeStepFile, Boolean outputAll) {
this.lockDirectory = lockDirectory;
this.timeStepFile = timeStepFile;
try {
this.lockFileHandler = new LockFileHandler(lockDirectory);
} catch (Exception e) {
logger.error(e);
}
}
private Topography prepareTopographyWithTSF(Topography topography) throws IOException {
final char separator = ';';// TODO [task=feature] [priority=low] add config for this separator
// read TSF
CSVReader reader = new CSVReader(new FileReader(timeStepFile), separator);
List<String[]> myEntries = reader.readAll();
Collection<Pedestrian> pedestrians = topography.getElements(Pedestrian.class);
// form a map to easily search for a pedestrian
Map<Integer, Pedestrian> pedMap = new HashMap<>();
for (Pedestrian pedestrian : pedestrians) {
pedMap.put(pedestrian.getId(), pedestrian);
}
// this will contain all pedestrians that should be removed (i.e. present in the topography
// but not in the TSF)
Map<Integer, Pedestrian> pedRemoveMap = new HashMap<>(pedMap);
// create the pedestrians stated in the TSF file. If they already exist, just move them and
// set their next target.
int id = 0, nextTarget = 0;
double x = 0, y = 0, dx = 0, dy = 0, desiredSpeed = 0;
for (String[] strings : myEntries) {
if (strings.length == 5) {
id = Integer.parseInt(strings[0]);
x = Double.parseDouble(strings[1]);
y = Double.parseDouble(strings[2]);
nextTarget = Integer.parseInt(strings[3]);
// int nextSource = Integer.parseInt(strings[4]); // TODO [priority=low] [task=feature] set source id
} else if (strings.length == 8) {
id = Integer.parseInt(strings[0]);
x = Double.parseDouble(strings[1]);
y = Double.parseDouble(strings[2]);
dx = Double.parseDouble(strings[3]);
dy = Double.parseDouble(strings[4]);
nextTarget = Integer.parseInt(strings[5]);
// int nextSource = Integer.parseInt(strings[6]); // TODO [priority=low] [task=feature] set source id
desiredSpeed = Double.parseDouble(strings[7]);
} else {
reader.close();
StringBuilder line = new StringBuilder();
for (String s : strings) {
line.append(s);
line.append(separator);
}
throw new IllegalArgumentException(
String.format("The line '%s' does not have the correct format. Correct value separator: '%s'",
line.toString(), separator));
}
if (pedMap.containsKey(id)) {
pedMap.get(id).setPosition(new VPoint(x, y));
LinkedList<Integer> targetIds = new LinkedList<>();
targetIds.add(nextTarget);
pedMap.get(id).setTargets(targetIds);
// if we have a velocity given, set it
if (strings.length == 8 && !Double.isNaN(dx) && !Double.isNaN(dy)) {
pedMap.get(id).setVelocity(new Vector2D(dx, dy));
pedMap.get(id).setFreeFlowSpeed(desiredSpeed);
}
pedRemoveMap.remove(id);
} else {
// TODO [priority=low] [task=feature] set sourceId
Pedestrian p = new Pedestrian(new AttributesAgent(id), new Random());
p.setPosition(new VPoint(x, y));
p.setVelocity(new Vector2D(dx, dy));
LinkedList<Integer> targets = new LinkedList<>();
targets.add(nextTarget);
p.setTargets(targets);
p.setFreeFlowSpeed(desiredSpeed);
topography.addInitialElement(p);
}
}
for (Pedestrian pedestrian : pedRemoveMap.values()) {
topography.removeElement(pedestrian);
}
reader.close();
return topography;
}
/**
* This adds the writers of the output and time-step-file to the simulation.
* Needed when in [lock] mode.
*
* @param simulation
* @throws FileNotFoundException
*/
private void prepareLockOutput(Simulation simulation) throws FileNotFoundException {
}
}
......@@ -114,9 +114,14 @@ public class ScenarioRunManager implements Runnable {
*/
@Override
public void run() {
doBeforeSimulation();
try {
logger.info(String.format("Initializing scenario. Start of scenario '%s'...", this.getName()));
if (finishedListener != null)
this.finishedListener.scenarioStarted(this);
scenarioStore.topography.reset();
MainModelBuilder modelBuilder = new MainModelBuilder(scenarioStore);
modelBuilder.createModelAndRandom();
......@@ -124,7 +129,7 @@ public class ScenarioRunManager implements Runnable {
final Random random = modelBuilder.getRandom();
// prepare processors and simulation data writer
this.processorManager = dataProcessingJsonManager.createProcessorManager(mainModel);
processorManager = dataProcessingJsonManager.createProcessorManager(mainModel);
createAndSetOutputDirectory();
......@@ -132,6 +137,8 @@ public class ScenarioRunManager implements Runnable {
out.println(JsonConverter.serializeScenarioRunManager(this, true));
}
sealAllAttributes();
// Run simulation main loop from start time = 0 seconds
simulation = new Simulation(mainModel, 0, scenarioStore.name, scenarioStore, passiveCallbacks, random, processorManager);
simulation.run();
......@@ -162,12 +169,9 @@ public class ScenarioRunManager implements Runnable {
(isSuccessful() ? "SUCCESSFUL" : "FAILURE")));
}
protected void doBeforeSimulation() {
if (finishedListener != null)
finishedListener.scenarioStarted(this);
logger.info(String.format("Initializing scenario. Start of scenario '%s'...", getName()));
scenarioStore.topography.reset();
private void sealAllAttributes() {
scenarioStore.sealAllAttributes();
processorManager.sealAllAttributes();
}
// Getter...
......@@ -236,7 +240,7 @@ public class ScenarioRunManager implements Runnable {
}
public void setAttributesModel(List<Attributes> attributesList) {
this.scenarioStore.attributesList = attributesList;
scenarioStore.attributesList = attributesList;
}
public void setAttributesPedestrian(AttributesAgent attributesPedestrian) {
......
......@@ -60,5 +60,11 @@ public class ScenarioStore {
public String hashOfJsonRepresentation() throws JsonProcessingException {
return DigestUtils.sha1Hex(StateJsonConverter.serializeObject(this));
}
public void sealAllAttributes() {
attributesList.forEach(a -> a.seal());
attributesSimulation.seal();
topography.sealAllAttributes();
}
}
......@@ -270,7 +270,7 @@ public class DataProcessingJsonManager {
}
public ProcessorManager createProcessorManager(MainModel mainModel) {
return new ProcessorManager(this, this.dataProcessors, this.outputFiles, mainModel);
return new ProcessorManager(this, dataProcessors, outputFiles, mainModel);
}
public int getMaxProcessorsId() {
......@@ -282,4 +282,5 @@ public class DataProcessingJsonManager {
}
return maxId;
}
}
......@@ -78,4 +78,8 @@ public class ProcessorManager {
public JsonNode serializeToNode() throws JsonProcessingException {
return this.jsonManager.serializeToNode();
}
public void sealAllAttributes() {
processorMap.values().forEach(p -> p.sealAttributes());
}
}
......@@ -65,7 +65,7 @@ public abstract class DataProcessor<K extends DataKey<K>, V> {
}
public AttributesProcessor getAttributes() {
return this.attributes;
return attributes;
}
public void setAttributes(AttributesProcessor attributes) {
......@@ -129,4 +129,10 @@ public abstract class DataProcessor<K extends DataKey<K>, V> {
public String toString() {
return id + ": " + getType();
}
public void sealAttributes() {
if (attributes != null) // some processors might not have attributes
attributes.seal();
}
}
......@@ -31,5 +31,10 @@
<artifactId>utils</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>commons-attributes</groupId>
<artifactId>commons-attributes-api</artifactId>
<version>2.2</version>
</dependency>
</dependencies>
</project>
package org.vadere.state.attributes;
import org.apache.commons.attributes.DefaultSealable;
/**
* Abstract class for all static simulation attributes. Provides reflection
* based methods to convert the fields and values of the Attributes classes from
* and to key-value store.
* Abstract base class for all static simulation attributes.
*
* Implementations must provide a no-arg default contstructor (either implicitly
* or explicitly) to enable deserialization from JSON.
*
* Attributes are "static" parameters i.e. they are immutable while a simulation
* is running. This is implemented by deriving from the
* {@link org.apache.commons.attributes.Sealable} interface. Attributes can have
* setters, but the setters must call the {@code checkSealed()} method before
* changing a value! In addition, if an attributes class contains other
* attributes classes as fields, it must override {@link #seal()} to also seal
* these objects. All other fields must be immutable (e.g. String, Double,
* VPoint,...).
*
*/
public abstract class Attributes {
public abstract class Attributes extends DefaultSealable {
}
......@@ -7,7 +7,6 @@ import org.vadere.util.reflection.DynamicClassInstantiator;
/**
* POJO for the model definition.
*
*
*/
public class ModelDefinition {
......
......@@ -13,6 +13,7 @@ public class AttributesPedestrianDensityCountingProcessor extends AttributesPede
}
public void setRadius(double radius) {
checkSealed();
this.radius = radius;
}
}
......@@ -13,6 +13,7 @@ public class AttributesPedestrianDensityProcessor extends AttributesProcessor {
}
public void setPedestrianPositionProcessorId(int pedestrianPositionProcessorId) {
checkSealed();
this.pedestrianPositionProcessorId = pedestrianPositionProcessorId;
}
}
......@@ -14,6 +14,7 @@ public class AttributesPedestrianVelocityProcessor extends AttributesProcessor {
}
public void setPedestrianPositionProcessorId(int pedestrianPositionProcessorId) {
checkSealed();
this.pedestrianPositionProcessorId = pedestrianPositionProcessorId;
}
......@@ -22,6 +23,7 @@ public class AttributesPedestrianVelocityProcessor extends AttributesProcessor {
}
public void setBackSteps(int backSteps) {
checkSealed();
this.backSteps = backSteps;
}
}
......@@ -2,5 +2,10 @@ package org.vadere.state.attributes.processor;
import org.vadere.state.attributes.Attributes;
/**
* Attributes for data processors.
*
* Please check the documentation of {@link org.vadere.state.attributes.Attributes}.
*/
public abstract class AttributesProcessor extends Attributes {
}
......@@ -39,9 +39,11 @@ public class AttributesCar extends AttributesAgent {
}
public void setDirection(Vector2D direction) {
checkSealed();
this.direction = direction;
}
@Override
public double getRadius() {
if (width >= length) {
return width;
......
......@@ -6,6 +6,7 @@ import java.util.*;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import org.vadere.state.attributes.Attributes;
import org.vadere.state.attributes.scenario.AttributesAgent;
import org.vadere.state.attributes.scenario.AttributesCar;
import org.vadere.state.attributes.scenario.AttributesDynamicElement;
......@@ -40,6 +41,13 @@ public class Topography {
*/
private final LinkedList<Target> targets;
/**
* List of obstacles used as a boundary for the whole topography.
*/
private List<Obstacle> boundaryObstacles;
private final List<Stairs> stairs;
private Teleporter teleporter;
private transient final DynamicElementContainer<Pedestrian> pedestrians;
......@@ -48,29 +56,50 @@ public class Topography {
private AttributesAgent attributesPedestrian;
private AttributesCar attributesCar;
/**
* List of obstacles used as a boundary for the whole topography.
*/
private List<Obstacle> boundaryObstacles;
private final List<Stairs> stairs;
/** Used to get attributes of all scenario elements. */
private Set<List<? extends ScenarioElement>> allScenarioElements = new HashSet<>(); // will be filled in the constructor