Compare commits
5 Commits
c68d9ab807
...
trunk
| Author | SHA1 | Date | |
|---|---|---|---|
| 112683ea42 | |||
| 8f47875cd7 | |||
| 05a3a88f83 | |||
| a5984f037e | |||
| 95bc1363f9 |
@@ -1,4 +1,6 @@
|
|||||||
# untitled
|
# Sensor Simulation
|
||||||
|
|
||||||
|
Sensor simulation that focuses on generating high volumes of sensor output. The output can be used to simulate faulty and correct behaviour, based on a ground truth. To remove the requirement of collecting and compose ground truth values for specific scenarios, the simulation also allows for a ground truth to be automatically generated during the simulation. The simulation is fully controllable and creates reproducible outputs with a given configuration.
|
||||||
|
|
||||||
## Wiki
|
## Wiki
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
simulation:
|
simulation:
|
||||||
duration: 24
|
duration: 24
|
||||||
tickfactor: 10
|
tickfactor: 1
|
||||||
runs: 1
|
runs: 1
|
||||||
parCell: 0
|
parCell: 0
|
||||||
parCellThreads: 5
|
parCellThreads: 5
|
||||||
@@ -19,10 +19,7 @@ sensors:
|
|||||||
- [1, 1, 5]
|
- [1, 1, 5]
|
||||||
- [2, 2, 5]
|
- [2, 2, 5]
|
||||||
- [3, 3, 5]
|
- [3, 3, 5]
|
||||||
blocks:
|
- [4, 4, 5]
|
||||||
- start: [0, 4]
|
|
||||||
end: [6, 6]
|
|
||||||
count: 210
|
|
||||||
|
|
||||||
- group: faultyTemp
|
- group: faultyTemp
|
||||||
parent: temperature
|
parent: temperature
|
||||||
@@ -36,40 +33,47 @@ sensors:
|
|||||||
cells:
|
cells:
|
||||||
- [3, 3, 5]
|
- [3, 3, 5]
|
||||||
|
|
||||||
# all cells are declared to output the gt
|
# all cells are declared to output the gt
|
||||||
# of baseline for each into the console
|
# of baseline for each into the console
|
||||||
- group: baseline
|
- group: baseline
|
||||||
cells:
|
blocks:
|
||||||
- [0, 0, 0]
|
- [0, 0, 0]
|
||||||
- [1, 1, 0]
|
- [1, 1, 0]
|
||||||
- [2, 2, 0]
|
- [2, 2, 0]
|
||||||
- [3, 3, 0]
|
- [3, 3, 0]
|
||||||
|
- [4, 4, 0]
|
||||||
|
|
||||||
groundtruths:
|
groundtruths:
|
||||||
- group: baseline
|
- group: baseline
|
||||||
truth:
|
truth:
|
||||||
- value: 10.0
|
- value: 7.0
|
||||||
timeline:
|
timeline:
|
||||||
- start: 0
|
- start: 0
|
||||||
end: 7
|
end: 2
|
||||||
- [18, 24]
|
- [19, 22]
|
||||||
- [7, 10]
|
- [2, 7.0]
|
||||||
- [12, 16.0]
|
- [22, 7.0]
|
||||||
delta:
|
delta:
|
||||||
- name: fluctuate
|
- name: fluctuate
|
||||||
args: {range: 0.0, center: [3, 3], distOffset: -0.5, time:[0, 12, 18]}
|
args: {range: 0.0, center: [3, 3], distOffset: -0.5, time:[0, 19, 22]}
|
||||||
timeline:
|
timeline:
|
||||||
- [0, 7]
|
- [0, 2]
|
||||||
- [12, 16]
|
- [3, 5]
|
||||||
- [18, 24]
|
- [8, 9]
|
||||||
- [7, change, {range: 0.0, target: 16.0, targetTime: 12, center: [3, 3], distOffset: -0.5, time:[7]}]
|
- [19, 22]
|
||||||
- [16, change, {range: 0.0, target: 10.0, targetTime: 18, center: [3, 3], distOffset: -0.5, time:[]}]
|
- [23, 24]
|
||||||
|
- [2, change, {range: 0.0, target: 6.0, targetTime: 3, center: [3, 3], distOffset: -0.5, time:[2]}]
|
||||||
|
- [5, change, {range: 0.0, target: 4.0, targetTime: 7, center: [3, 3], distOffset: -0.5, time:[]}]
|
||||||
|
- [7, change, {range: 0.0, target: 5.0, targetTime: 8, center: [3, 3], distOffset: -0.5, time:[]}]
|
||||||
|
- [9, change, {range: 0.0, target: 9.0, targetTime: 17, center: [3, 3], distOffset: -0.5, time:[]}]
|
||||||
|
- [17, change, {range: 0.0, target: 7.0, targetTime: 19, center: [3, 3], distOffset: -0.5, time:[]}]
|
||||||
|
- [22, change, {range: 0.0, target: 6.0, targetTime: 23, center: [3, 3], distOffset: -0.5, time:[22]}]
|
||||||
|
|
||||||
- group: temperature
|
- group: temperature
|
||||||
parent: baseline
|
parent: baseline
|
||||||
delta:
|
delta:
|
||||||
- name: fluctuate
|
- name: fluctuate
|
||||||
args: {range: 1.0}
|
args: {range: 0.3}
|
||||||
timeline:
|
timeline:
|
||||||
- [0, 7]
|
- [0, 7]
|
||||||
- [12, 16]
|
- [12, 16]
|
||||||
@@ -98,23 +102,23 @@ behaviours:
|
|||||||
|
|
||||||
- group: faultyTemp
|
- group: faultyTemp
|
||||||
functions:
|
functions:
|
||||||
- name: measureTemp
|
- name: measureTemp
|
||||||
args:
|
args:
|
||||||
range: [-50.0, 150.0]
|
range: [-50.0, 150.0]
|
||||||
resolution: 0.1
|
resolution: 0.1
|
||||||
accuracy: 1.0
|
accuracy: 1.0
|
||||||
offset: 10.0
|
offset: 10.0
|
||||||
timeline:
|
timeline:
|
||||||
- [0, 12]
|
- [0, 12]
|
||||||
- [12, noOutput, {}]
|
- [12, noOutput, {}]
|
||||||
- name: measureTemp
|
- name: measureTemp
|
||||||
args:
|
args:
|
||||||
range: [-50.0, 150.0]
|
range: [-50.0, 150.0]
|
||||||
resolution: 0.1
|
resolution: 0.1
|
||||||
accuracy: 20.0
|
accuracy: 20.0
|
||||||
offset: 0.0
|
offset: 0.0
|
||||||
timeline:
|
timeline:
|
||||||
- [15, 24]
|
- [15, 24]
|
||||||
|
|
||||||
- group: humidity
|
- group: humidity
|
||||||
functions:
|
functions:
|
||||||
|
|||||||
@@ -8,11 +8,12 @@ import scim.lib.simInterfaces.SimulationBehaviour
|
|||||||
object Main {
|
object Main {
|
||||||
// o7
|
// o7
|
||||||
def main(args: Array[String]): Unit = {
|
def main(args: Array[String]): Unit = {
|
||||||
startSimulation()
|
val file = if(args.length > 0) args(0) else "docs/wiki/config/config_due.yml"
|
||||||
|
startSimulation(file)
|
||||||
}
|
}
|
||||||
|
|
||||||
def startSimulation(): Unit = {
|
def startSimulation(file: String): Unit = {
|
||||||
val config = new Parser().parse("docs/wiki/config/config_preview.yml", scim.components.behaviour.behaviours)
|
val config = new Parser().parse(file, scim.components.behaviour.behaviours)
|
||||||
val sharedMemory = config.sharedMemory
|
val sharedMemory = config.sharedMemory
|
||||||
val output = new Output(sharedMemory)
|
val output = new Output(sharedMemory)
|
||||||
val simulator = new Simulation(config)
|
val simulator = new Simulation(config)
|
||||||
|
|||||||
@@ -1,214 +1,214 @@
|
|||||||
package scim.components
|
package scim.components
|
||||||
|
|
||||||
import scim.datastruct.{Cell, FunctionArgs, SimulationBehaviours, Time}
|
import scim.datastruct.{Cell, FunctionArgs, SimulationBehaviours, Time}
|
||||||
import scim.lib.numberUtil._
|
import scim.lib.numberUtil._
|
||||||
import scim.lib.mapUtil._
|
import scim.lib.mapUtil._
|
||||||
import scim.lib.behaviourUtil._
|
import scim.lib.behaviourUtil._
|
||||||
import scim.lib.simInterfaces.SimulationBehaviour
|
import scim.lib.simInterfaces.SimulationBehaviour
|
||||||
|
|
||||||
import scala.util.Random
|
import scala.util.Random
|
||||||
|
|
||||||
package object behaviour {
|
package object behaviour {
|
||||||
|
|
||||||
val behaviours = SimulationBehaviours(Map[String, SimulationBehaviour](
|
val behaviours = SimulationBehaviours(Map[String, SimulationBehaviour](
|
||||||
"measureGeneric" -> measureGeneric,
|
"measureGeneric" -> measureGeneric,
|
||||||
"measureTemp" -> measureTemp,
|
"measureTemp" -> measureTemp,
|
||||||
"measureHumid" -> measureHumid,
|
"measureHumid" -> measureHumid,
|
||||||
"noOutput" -> noOutput,
|
"noOutput" -> noOutput,
|
||||||
"randomOutput" -> randomOutput,
|
"randomOutput" -> randomOutput,
|
||||||
"measureTempMod" -> measureTempMod,
|
"measureTempMod" -> measureTempMod,
|
||||||
"fluctuate" -> fluctuate,
|
"fluctuate" -> fluctuate,
|
||||||
"change" -> change,
|
"change" -> change,
|
||||||
"humidFromTemp" -> humidFromTemp
|
"humidFromTemp" -> humidFromTemp
|
||||||
))
|
))
|
||||||
|
|
||||||
def measureGeneric: SimulationBehaviour = {
|
def measureGeneric: SimulationBehaviour = {
|
||||||
sensorFactory(Vector(0, 1), 0.1, 0.1, 0.0)
|
sensorFactory(Vector(0, 1), 0.1, 0.1, 0.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
def measureTemp: SimulationBehaviour = {
|
def measureTemp: SimulationBehaviour = {
|
||||||
sensorFactory(Vector(-50, 150), 0.1, 1.0, 0.0)
|
sensorFactory(Vector(-50, 150), 0.1, 1.0, 0.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
def measureHumid: SimulationBehaviour = {
|
def measureHumid: SimulationBehaviour = {
|
||||||
sensorFactory(Vector(5, 100), 1.0, 2.0, 0.0)
|
sensorFactory(Vector(5, 100), 1.0, 2.0, 0.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
def measureTempMod: SimulationBehaviour = {
|
def measureTempMod: SimulationBehaviour = {
|
||||||
sensorModifierFactory("accuracy", Vector(-10, 10), 5, 15.0, 20.0, measureTemp)
|
sensorModifierFactory("accuracy", Vector(-10, 10), 5, 15.0, 20.0, measureTemp)
|
||||||
}
|
}
|
||||||
|
|
||||||
def noOutput: SimulationBehaviour = {
|
def noOutput: SimulationBehaviour = {
|
||||||
(_: Cell, _: Time, _: Option[Double], _: Option[FunctionArgs]) => { None }
|
(_: Cell, _: Time, _: Option[Double], _: Option[FunctionArgs]) => { None }
|
||||||
}
|
}
|
||||||
|
|
||||||
def randomOutput: SimulationBehaviour = {
|
def randomOutput: SimulationBehaviour = {
|
||||||
randomOutputFactory(Vector(-50, 50))
|
randomOutputFactory(Vector(-50, 50))
|
||||||
}
|
}
|
||||||
|
|
||||||
def randomOutputFactory(defaultRange: Vector[Double]) : SimulationBehaviour = {
|
def randomOutputFactory(defaultRange: Vector[Double]) : SimulationBehaviour = {
|
||||||
(_: Cell, _: Time, _: Option[Double], args: Option[FunctionArgs]) => {
|
(_: Cell, _: Time, _: Option[Double], args: Option[FunctionArgs]) => {
|
||||||
val range: Vector[Double] = args.getParam("range", defaultRange)
|
val range: Vector[Double] = args.getParam("range", defaultRange)
|
||||||
val rng = new Random()
|
val rng = new Random()
|
||||||
val start = range(0).intValue()
|
val start = range(0).intValue()
|
||||||
val end = range(1).intValue()
|
val end = range(1).intValue()
|
||||||
val rngRange = start + rng.nextInt((end - start) + 1)
|
val rngRange = start + rng.nextInt((end - start) + 1)
|
||||||
Some((rngRange.doubleValue() + rng.nextDouble() * (if (rng.nextBoolean()) -1 else 1)).range(range(0), range(1)))
|
Some((rngRange.doubleValue() + rng.nextDouble() * (if (rng.nextBoolean()) -1 else 1)).range(range(0), range(1)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def sensorModifierFactory(defaultMod: String, modRange: Vector[Double], modResolution: Double, modAccuracy: Double, modOffset: Double,
|
def sensorModifierFactory(defaultMod: String, modRange: Vector[Double], modResolution: Double, modAccuracy: Double, modOffset: Double,
|
||||||
behaviour: SimulationBehaviour): SimulationBehaviour = {
|
behaviour: SimulationBehaviour): SimulationBehaviour = {
|
||||||
def modifyArgs(args: Option[FunctionArgs]): Option[FunctionArgs] = {
|
def modifyArgs(args: Option[FunctionArgs]): Option[FunctionArgs] = {
|
||||||
val modifier: Option[Map[String, Any]] = args.getParam("modifier")
|
val modifier: Option[Map[String, Any]] = args.getParam("modifier")
|
||||||
if (!modifier.isEmpty) {
|
if (!modifier.isEmpty) {
|
||||||
val modType = modifier.get.getKeyOrElse[String]("type", defaultMod)
|
val modType = modifier.get.getKeyOrElse[String]("type", defaultMod)
|
||||||
// TODO: use interface to replace args
|
// TODO: use interface to replace args
|
||||||
val newArgs = modType match {
|
val newArgs = modType match {
|
||||||
case "range" => args.get.args + ("range" -> modifier.get.getKeyOrElse[Vector[Double]]("value", modRange))
|
case "range" => args.get.args + ("range" -> modifier.get.getKeyOrElse[Vector[Double]]("value", modRange))
|
||||||
case "resolution" => args.get.args + ("resolution" -> modifier.get.getKeyOrElse[Double]("value", modResolution))
|
case "resolution" => args.get.args + ("resolution" -> modifier.get.getKeyOrElse[Double]("value", modResolution))
|
||||||
case "accuracy" => args.get.args + ("accuracy" -> modifier.get.getKeyOrElse[Double]("value", modAccuracy))
|
case "accuracy" => args.get.args + ("accuracy" -> modifier.get.getKeyOrElse[Double]("value", modAccuracy))
|
||||||
case "offset" => args.get.args + ("offset" -> modifier.get.getKeyOrElse[Double]("value", modOffset))
|
case "offset" => args.get.args + ("offset" -> modifier.get.getKeyOrElse[Double]("value", modOffset))
|
||||||
}
|
}
|
||||||
Some(FunctionArgs(newArgs))
|
Some(FunctionArgs(newArgs))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val modifierWrapper: SimulationBehaviour = (cell: Cell, time: Time, inTruth: Option[Double], args: Option[FunctionArgs]) => {
|
val modifierWrapper: SimulationBehaviour = (cell: Cell, time: Time, inTruth: Option[Double], args: Option[FunctionArgs]) => {
|
||||||
val modifier: Option[Map[String, Any]] = args.getParam("modifier")
|
val modifier: Option[Map[String, Any]] = args.getParam("modifier")
|
||||||
if (!modifier.isEmpty) {
|
if (!modifier.isEmpty) {
|
||||||
val x = modifier.get.getKey[Int]("x")
|
val x = modifier.get.getKey[Int]("x")
|
||||||
val y = modifier.get.getKey[Int]("y")
|
val y = modifier.get.getKey[Int]("y")
|
||||||
val timeMod = modifier.get.getKey[Int]("time")
|
val timeMod = modifier.get.getKey[Int]("time")
|
||||||
(timeMod, x, y) match {
|
(timeMod, x, y) match {
|
||||||
case (timeFault, None, None) if (!timeFault.isEmpty && timeFault.get == time.time) => behaviour(cell, time, inTruth, modifyArgs(args))
|
case (timeFault, None, None) if (!timeFault.isEmpty && (timeFault.get * time.tickfactor.getOrElse(1)) == time.time) => behaviour(cell, time, inTruth, modifyArgs(args))
|
||||||
case (None, xVal, yVal) if (!xVal.isEmpty && !yVal.isEmpty && Cell(xVal.get, yVal.get) == cell) => behaviour(cell, time, inTruth, modifyArgs(args))
|
case (None, xVal, yVal) if (!xVal.isEmpty && !yVal.isEmpty && Cell(xVal.get, yVal.get) == cell) => behaviour(cell, time, inTruth, modifyArgs(args))
|
||||||
case (timeFault, xVal, yVal) if (!timeFault.isEmpty && timeFault.get == time.time && !xVal.isEmpty && !yVal.isEmpty && Cell(xVal.get, yVal.get) == cell) =>
|
case (timeFault, xVal, yVal) if (!timeFault.isEmpty && (timeFault.get * time.tickfactor.getOrElse(1)) == time.time && !xVal.isEmpty && !yVal.isEmpty && Cell(xVal.get, yVal.get) == cell) =>
|
||||||
behaviour(cell, time, inTruth, modifyArgs(args))
|
behaviour(cell, time, inTruth, modifyArgs(args))
|
||||||
case _ => behaviour(cell, time, inTruth, args)
|
case _ => behaviour(cell, time, inTruth, args)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
behaviour(cell, time, inTruth, args)
|
behaviour(cell, time, inTruth, args)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
modifierWrapper
|
modifierWrapper
|
||||||
}
|
}
|
||||||
|
|
||||||
def sensorFactory(defaultRange: Vector[Double], defaultResolution: Double, defaultAccuracy: Double, defaultOffset: Double,
|
def sensorFactory(defaultRange: Vector[Double], defaultResolution: Double, defaultAccuracy: Double, defaultOffset: Double,
|
||||||
altFunction: Option[SimulationBehaviour] = None,
|
altFunction: Option[SimulationBehaviour] = None,
|
||||||
preFunction: Option[SimulationBehaviour] = None,
|
preFunction: Option[SimulationBehaviour] = None,
|
||||||
postFunction: Option[SimulationBehaviour] = None): SimulationBehaviour = {
|
postFunction: Option[SimulationBehaviour] = None): SimulationBehaviour = {
|
||||||
|
|
||||||
val genericSensor: SimulationBehaviour = (cell: Cell, time: Time, inTruth: Option[Double], args: Option[FunctionArgs]) => {
|
val genericSensor: SimulationBehaviour = (cell: Cell, time: Time, inTruth: Option[Double], args: Option[FunctionArgs]) => {
|
||||||
// can use altFunction to entirely disable normal behaviour (including pre/postFunction)
|
// can use altFunction to entirely disable normal behaviour (including pre/postFunction)
|
||||||
// useful when trying to use different params based on cell/time
|
// useful when trying to use different params based on cell/time
|
||||||
val altResult = if (!altFunction.isEmpty) altFunction.get(cell, time, inTruth, args) else None
|
val altResult = if (!altFunction.isEmpty) altFunction.get(cell, time, inTruth, args) else None
|
||||||
if (!altResult.isEmpty) {
|
if (!altResult.isEmpty) {
|
||||||
altResult
|
altResult
|
||||||
} else {
|
} else {
|
||||||
// preFunction can modify ground truth
|
// preFunction can modify ground truth
|
||||||
// can e.g. be used to return None or modify truth based on cell/time
|
// can e.g. be used to return None or modify truth based on cell/time
|
||||||
val preResult = if (!preFunction.isEmpty) preFunction.get(cell, time, inTruth, args) else inTruth
|
val preResult = if (!preFunction.isEmpty) preFunction.get(cell, time, inTruth, args) else inTruth
|
||||||
if (preResult.isEmpty) {
|
if (preResult.isEmpty) {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
val truth = preResult.get
|
val truth = preResult.get
|
||||||
val range: Vector[Double] = args.getParam("range", defaultRange) // using a vector to match yml parsing
|
val range: Vector[Double] = args.getParam("range", defaultRange) // using a vector to match yml parsing
|
||||||
val resolution: Double = args.getParam("resolution", defaultResolution)
|
val resolution: Double = args.getParam("resolution", defaultResolution)
|
||||||
val accuracy: Double = args.getParam("accuracy", defaultAccuracy)
|
val accuracy: Double = args.getParam("accuracy", defaultAccuracy)
|
||||||
val offset: Double = args.getParam("offset", defaultOffset)
|
val offset: Double = args.getParam("offset", defaultOffset)
|
||||||
val rng = new Random()
|
val rng = new Random()
|
||||||
val rngAcc = rng.nextDouble() * accuracy * (if (rng.nextBoolean()) -1 else 1)
|
val rngAcc = rng.nextDouble() * accuracy * (if (rng.nextBoolean()) -1 else 1)
|
||||||
val result: Option[Double] = Some((truth + rngAcc + offset).resolution(resolution).range(range(0), range(1)))
|
val result: Option[Double] = Some((truth + rngAcc + offset).resolution(resolution).range(range(0), range(1)))
|
||||||
// postFunction can modify result
|
// postFunction can modify result
|
||||||
// can e.g. be used to modify result based on cell, time and result itself
|
// can e.g. be used to modify result based on cell, time and result itself
|
||||||
// (e.g. return garbage when result is above threshold to simulate failure above threshold)
|
// (e.g. return garbage when result is above threshold to simulate failure above threshold)
|
||||||
if (!postFunction.isEmpty) postFunction.get(cell, time, result, args) else result
|
if (!postFunction.isEmpty) postFunction.get(cell, time, result, args) else result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
genericSensor
|
genericSensor
|
||||||
}
|
}
|
||||||
|
|
||||||
def sensorFactoryBehaviour(default: SimulationBehaviour,
|
def sensorFactoryBehaviour(default: SimulationBehaviour,
|
||||||
altFunction: Option[SimulationBehaviour] = None,
|
altFunction: Option[SimulationBehaviour] = None,
|
||||||
preFunction: Option[SimulationBehaviour] = None,
|
preFunction: Option[SimulationBehaviour] = None,
|
||||||
postFunction: Option[SimulationBehaviour] = None): SimulationBehaviour = {
|
postFunction: Option[SimulationBehaviour] = None): SimulationBehaviour = {
|
||||||
|
|
||||||
val genericSensor: SimulationBehaviour = (cell: Cell, time: Time, inTruth: Option[Double], args: Option[FunctionArgs]) => {
|
val genericSensor: SimulationBehaviour = (cell: Cell, time: Time, inTruth: Option[Double], args: Option[FunctionArgs]) => {
|
||||||
val altResult = if (!altFunction.isEmpty) altFunction.get(cell, time, inTruth, args) else None
|
val altResult = if (!altFunction.isEmpty) altFunction.get(cell, time, inTruth, args) else None
|
||||||
if (!altResult.isEmpty) {
|
if (!altResult.isEmpty) {
|
||||||
altResult
|
altResult
|
||||||
} else {
|
} else {
|
||||||
val preResult = if (!preFunction.isEmpty) preFunction.get(cell, time, inTruth, args) else inTruth
|
val preResult = if (!preFunction.isEmpty) preFunction.get(cell, time, inTruth, args) else inTruth
|
||||||
if (preResult.isEmpty) {
|
if (preResult.isEmpty) {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
val result = default(cell, time, inTruth, args)
|
val result = default(cell, time, inTruth, args)
|
||||||
if (!postFunction.isEmpty) postFunction.get(cell, time, result, args) else result
|
if (!postFunction.isEmpty) postFunction.get(cell, time, result, args) else result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
genericSensor
|
genericSensor
|
||||||
}
|
}
|
||||||
|
|
||||||
def fluctuate (cell: Cell, time: Time, inTruth: Option[Double], args: Option[FunctionArgs]): Option[Double] = {
|
def fluctuate (cell: Cell, time: Time, inTruth: Option[Double], args: Option[FunctionArgs]): Option[Double] = {
|
||||||
if(inTruth.isEmpty) return None
|
if(inTruth.isEmpty) return None
|
||||||
val range: Double = args.getParam("range", 1.0)
|
val range: Double = args.getParam("range", 0.0)
|
||||||
val center: Vector[Int] = args.getParam("center", Vector(0, 0))
|
val center: Vector[Int] = args.getParam("center", Vector(0, 0))
|
||||||
val distOffset: Option[Double] = args.getParam[Double]("distOffset")
|
val distOffset: Option[Double] = args.getParam[Double]("distOffset")
|
||||||
val offsetTimes: Option[Vector[Int]] = args.getParam[Vector[Int]]("time")
|
val offsetTimes: Option[Vector[Int]] = args.getParam[Vector[Int]]("time")
|
||||||
val offset = if(!distOffset.isEmpty && offsetTimes.get.contains(time.time)) {
|
val offset = if(!distOffset.isEmpty && offsetTimes.get.contains(time.getNormalized().getOrElse(-1))) {
|
||||||
val centerCell = Cell(center(0), center(1))
|
val centerCell = Cell(center(0), center(1))
|
||||||
centerCell.distance(cell) * distOffset.get
|
centerCell.distance(cell) * distOffset.get
|
||||||
} else { 0 }
|
} else { 0 }
|
||||||
|
|
||||||
val rng = new Random()
|
val rng = new Random()
|
||||||
val rngRange = rng.nextDouble() * range * (if (rng.nextBoolean()) -1 else 1)
|
val rngRange = rng.nextDouble() * range * (if (rng.nextBoolean()) -1 else 1)
|
||||||
|
|
||||||
Some(inTruth.get + rngRange + offset)
|
Some(inTruth.get + rngRange + offset)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def change (cell: Cell, time: Time, inTruth: Option[Double], args: Option[FunctionArgs]): Option[Double] = {
|
def change (cell: Cell, time: Time, inTruth: Option[Double], args: Option[FunctionArgs]): Option[Double] = {
|
||||||
if(inTruth.isEmpty) return None
|
if(inTruth.isEmpty) return None
|
||||||
val range: Double = args.getParam("range", 1.0)
|
val range: Double = args.getParam("range", 0.0)
|
||||||
val target: Double = args.getParam("target", inTruth.get + 5)
|
val target: Double = args.getParam("target", inTruth.get + 5)
|
||||||
val targetTime: Int = args.getParam("targetTime", time.time + 1)
|
val targetTime: Int = args.getParam("targetTime", time.getNormalized + 1) * time.tickfactor.getOrElse(1) + 1
|
||||||
val center: Vector[Int] = args.getParam("center", Vector(0, 0))
|
val center: Vector[Int] = args.getParam("center", Vector(0, 0))
|
||||||
val distOffset: Option[Double] = args.getParam[Double]("distOffset")
|
val distOffset: Option[Double] = args.getParam[Double]("distOffset")
|
||||||
val offsetTimes: Option[Vector[Int]] = args.getParam[Vector[Int]]("time")
|
val offsetTimes: Option[Vector[Int]] = args.getParam[Vector[Int]]("time")
|
||||||
// always calculate offset for target
|
// always calculate offset for target
|
||||||
val offset = if(!distOffset.isEmpty) {
|
val offset = if(!distOffset.isEmpty) {
|
||||||
val centerCell = Cell(center(0), center(1))
|
val centerCell = Cell(center(0), center(1))
|
||||||
centerCell.distance(cell) * distOffset.get
|
centerCell.distance(cell) * distOffset.get
|
||||||
} else { 0 }
|
} else { 0 }
|
||||||
|
|
||||||
// only change truth on offsetTimes
|
// only change truth on offsetTimes
|
||||||
val truth = if(!offsetTimes.isEmpty && offsetTimes.get.contains(time.time)) inTruth.get + offset else inTruth.get
|
val truth = if(!offsetTimes.isEmpty && offsetTimes.get.contains(time.getNormalized().getOrElse(-1))) inTruth.get + offset else inTruth.get
|
||||||
|
|
||||||
val rng = new Random()
|
val rng = new Random()
|
||||||
val rngRange = rng.nextDouble() * range * (if (rng.nextBoolean()) -1 else 1)
|
val rngRange = rng.nextDouble() * range * (if (rng.nextBoolean()) -1 else 1)
|
||||||
val step: Double = if(time.time < targetTime) {
|
val step: Double = if(time.time < targetTime) {
|
||||||
(target + offset - truth) / (targetTime - time.time).toDouble
|
(target + offset - truth) / (targetTime - time.time).toDouble
|
||||||
} else { 0 }
|
} else { 0 }
|
||||||
|
|
||||||
Some(inTruth.get + rngRange + step)
|
Some(truth + rngRange + step)
|
||||||
}
|
}
|
||||||
|
|
||||||
def humidFromTemp (cell: Cell, time: Time, inTruth: Option[Double], args: Option[FunctionArgs]): Option[Double] = {
|
def humidFromTemp (cell: Cell, time: Time, inTruth: Option[Double], args: Option[FunctionArgs]): Option[Double] = {
|
||||||
if(inTruth.isEmpty) return None
|
if(inTruth.isEmpty) return None
|
||||||
val dewpoint: Double = args.getParam("dewpoint", 12.0)
|
val dewpoint: Double = args.getParam("dewpoint", 12.0)
|
||||||
val temp: Double = inTruth.get
|
val temp: Double = inTruth.get
|
||||||
|
|
||||||
// source: https://bmcnoldy.rsmas.miami.edu/Humidity.html
|
// source: https://bmcnoldy.rsmas.miami.edu/Humidity.html
|
||||||
val rh = 100*(Math.exp((17.625*dewpoint)/(243.04+dewpoint))/Math.exp((17.625*temp)/(243.04+temp)))
|
val rh = 100*(Math.exp((17.625*dewpoint)/(243.04+dewpoint))/Math.exp((17.625*temp)/(243.04+temp)))
|
||||||
Some(rh)
|
Some(rh)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,16 +2,27 @@ package scim.components
|
|||||||
|
|
||||||
import scim.datastruct.{Cell, Group, SensorResult, SharedMemory, Time, Truth}
|
import scim.datastruct.{Cell, Group, SensorResult, SharedMemory, Time, Truth}
|
||||||
import scim.lib.consoleUtil.Color._
|
import scim.lib.consoleUtil.Color._
|
||||||
|
import scim.lib.io._
|
||||||
|
|
||||||
class Output(sharedMemory: SharedMemory, printOutput: Boolean = true) extends Runnable {
|
class Output(sharedMemory: SharedMemory, printOutput: Boolean = true) extends Runnable {
|
||||||
|
val outputFileBaseline = OutputFile("baseline.txt")
|
||||||
|
val outputFileTemperature = OutputFile("temperature.txt")
|
||||||
|
val outputFileFaultyTemp = OutputFile("faultyTemp.txt")
|
||||||
|
val outputFileSensor = OutputFile("sensor_temp.txt")
|
||||||
|
val outputFileFaultySensor = OutputFile("sensor_fault.txt")
|
||||||
def run(): Unit = {
|
def run(): Unit = {
|
||||||
val duration = sharedMemory.config.duration
|
val duration = sharedMemory.config.getDuration
|
||||||
def outputHelper(time: Time): Unit = {
|
def outputHelper(time: Time): Unit = {
|
||||||
val simOutput = sharedMemory.subscribe(time)
|
val simOutput = sharedMemory.subscribe(time)
|
||||||
outputData(time, simOutput._1, simOutput._2)
|
outputData(time, simOutput._1, simOutput._2)
|
||||||
}
|
}
|
||||||
|
//outputFile.buffer("group,time,x,y,gt\n")
|
||||||
Vector.tabulate(sharedMemory.config.duration)(t => Time(t, duration)).foreach(outputHelper)
|
Vector.tabulate(duration)(t => Time(t, duration)).foreach(outputHelper)
|
||||||
|
outputFileBaseline.write()
|
||||||
|
outputFileTemperature.write()
|
||||||
|
outputFileFaultyTemp.write()
|
||||||
|
outputFileSensor.write()
|
||||||
|
outputFileFaultySensor.write()
|
||||||
}
|
}
|
||||||
|
|
||||||
def outputData(time: Time, sensors: Map[Cell, Map[Group, Vector[SensorResult]]], groundTruths: Map[Cell, Map[Group, Truth]]): Unit = {
|
def outputData(time: Time, sensors: Map[Cell, Map[Group, Vector[SensorResult]]], groundTruths: Map[Cell, Map[Group, Truth]]): Unit = {
|
||||||
@@ -28,6 +39,22 @@ class Output(sharedMemory: SharedMemory, printOutput: Boolean = true) extends Ru
|
|||||||
groups._2.foreach(res => print(res.get._3.getOrElse("None") + (if(res.eq(lastElement.get)) "" else " | ")))
|
groups._2.foreach(res => print(res.get._3.getOrElse("None") + (if(res.eq(lastElement.get)) "" else " | ")))
|
||||||
if(groundTruths.contains(cell) && groundTruths(cell).contains(group)) print(GREEN("\n Ground Truth: ") + groundTruths(cell)(group).peak().getOrElse("None"))
|
if(groundTruths.contains(cell) && groundTruths(cell).contains(group)) print(GREEN("\n Ground Truth: ") + groundTruths(cell)(group).peak().getOrElse("None"))
|
||||||
print("\n")
|
print("\n")
|
||||||
|
|
||||||
|
val x = cell.x; val y = cell.y
|
||||||
|
val groupName = group.name
|
||||||
|
val groupParent = group.parent.getOrElse("");
|
||||||
|
val value = groundTruths(cell)(group).peak().getOrElse(None).getOrElse(None)
|
||||||
|
val sResult = if(groups._2.size > 0) groups._2(0).get._3.getOrElse(None) else None
|
||||||
|
if(groupName == "baseline") {
|
||||||
|
outputFileBaseline.buffer(time.time + "," + x + "," + y + "," + value.toString + "\n")
|
||||||
|
} else if(groupName == "temperature") {
|
||||||
|
outputFileTemperature.buffer(time.time + "," + x + "," + y + "," + value.toString + "\n")
|
||||||
|
outputFileSensor.buffer(time.time + "," + x + "," + y + "," + sResult.toString + "\n")
|
||||||
|
} else if(groupName == "faultyTemp") {
|
||||||
|
outputFileFaultyTemp.buffer(time.time + "," + x + "," + y + "," + value.toString + "\n")
|
||||||
|
outputFileFaultySensor.buffer(time.time + "," + x + "," + y + "," + sResult.toString + "\n")
|
||||||
|
}
|
||||||
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,323 +1,348 @@
|
|||||||
package scim.components
|
package scim.components
|
||||||
|
|
||||||
import scim.datastruct.{Behaviour, BehaviourVector, Cell, Configuration, FunctionArgs, GroundTruth, Group, Sensor, SensorCount, SensorResult, SharedMemory, SimulationBehaviours, SimulationConfig, Time, Truth}
|
import scim.datastruct.{Behaviour, BehaviourVector, Cell, Configuration, FunctionArgs, GroundTruth, Group, Sensor, SensorCount, SensorResult, SharedMemory, SimulationBehaviours, SimulationConfig, Time, Truth}
|
||||||
import scim.lib.debugUtil.{DebugType, debugf}
|
import scim.lib.debugUtil.{DebugType, debugf}
|
||||||
import scim.lib.mapUtil._
|
import scim.lib.mapUtil._
|
||||||
import scim.lib.simInterfaces.SimulationBehaviour
|
import scim.lib.simInterfaces.SimulationBehaviour
|
||||||
import scim.lib.yml
|
import scim.lib.yml
|
||||||
import scim.lib.parserUtil._
|
import scim.lib.parserUtil._
|
||||||
import scala.collection.mutable
|
import scala.collection.mutable
|
||||||
|
|
||||||
class Parser() {
|
class Parser() {
|
||||||
def parse(file: String, simulationBehaviours: SimulationBehaviours): Configuration = {
|
def parse(file: String, simulationBehaviours: SimulationBehaviours): Configuration = {
|
||||||
val parser = new SimulationConfigParser(yml.parse(file), simulationBehaviours)
|
val parser = new SimulationConfigParser(yml.parse(file), simulationBehaviours)
|
||||||
parser.parse()
|
parser.parse()
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// when creating (Group, Sensor, Option[GroundTruth]), keep ref in Map[Group, Sensor, Option[GroundTruth]] for all, to find
|
// when creating (Group, Sensor, Option[GroundTruth]), keep ref in Map[Group, Sensor, Option[GroundTruth]] for all, to find
|
||||||
// root group via group.parent (while !isempty get next) (maybe tree instead)
|
// root group via group.parent (while !isempty get next) (maybe tree instead)
|
||||||
|
|
||||||
// for cells s-> create Map[Group, Map[Cell, Count]]
|
// for cells s-> create Map[Group, Map[Cell, Count]]
|
||||||
// for gt g-> create Map[Group, GroundTruth]
|
// for gt g-> create Map[Group, GroundTruth]
|
||||||
// for behaviour b-> create Map[Group, Behaviour]
|
// for behaviour b-> create Map[Group, Behaviour]
|
||||||
// sensors = s.map(kv => (kv._1, kv._2.map(kv2 => (kv2._1, SENSOR, TRUTH)))
|
// sensors = s.map(kv => (kv._1, kv._2.map(kv2 => (kv2._1, SENSOR, TRUTH)))
|
||||||
// sensors.foreach(kv => kv._1
|
// sensors.foreach(kv => kv._1
|
||||||
|
|
||||||
class SimulationConfigParser(input: Map[String, Any], simulationBehaviours: SimulationBehaviours) {
|
class SimulationConfigParser(input: Map[String, Any], simulationBehaviours: SimulationBehaviours) {
|
||||||
private val config: SimulationConfig = parseSimulationConfig(input("simulation").asInstanceOf[Map[String, Any]])
|
private val config: SimulationConfig = parseSimulationConfig(input("simulation").asInstanceOf[Map[String, Any]])
|
||||||
private val groups = mutable.Map[String, Group]().empty
|
private val groups = mutable.Map[String, Group]().empty
|
||||||
private val sensorList = mutable.Map[Cell, mutable.Map[Group, SensorCount]]().empty
|
private val sensorList = mutable.Map[Cell, mutable.Map[Group, SensorCount]]().empty
|
||||||
private val behaviourListSensor = mutable.Map[Group, Behaviour]().empty
|
private val behaviourListSensor = mutable.Map[Group, Behaviour]().empty
|
||||||
private val behaviourListGroundTruth = mutable.Map[Group, Behaviour]().empty
|
private val behaviourListGroundTruth = mutable.Map[Group, Behaviour]().empty
|
||||||
private val groundTruthValues = mutable.Map[Time, mutable.Map[Group, Truth]]() // FIXME: are not parsed correctly
|
private val groundTruthValues = mutable.Map[Time, mutable.Map[Group, Truth]]() // FIXME: are not parsed correctly
|
||||||
// this will throw if the map doesn't contain what it should
|
// this will throw if the map doesn't contain what it should
|
||||||
@throws(classOf[Exception])
|
@throws(classOf[Exception])
|
||||||
def parse(): Configuration = {
|
def parse(): Configuration = {
|
||||||
|
|
||||||
val sensors = input("sensors").asInstanceOf[Vector[Map[String, Any]]]
|
val sensors = input("sensors").asInstanceOf[Vector[Map[String, Any]]]
|
||||||
val groundTruths = input("groundtruths").asInstanceOf[Vector[Map[String, Any]]]
|
val groundTruths = input("groundtruths").asInstanceOf[Vector[Map[String, Any]]]
|
||||||
val behaviours = input("behaviours").asInstanceOf[Vector[Map[String, Any]]]
|
val behaviours = input("behaviours").asInstanceOf[Vector[Map[String, Any]]]
|
||||||
|
|
||||||
sensors.foreach(sensor => parseSensor(sensor))
|
sensors.foreach(sensor => parseSensor(sensor))
|
||||||
behaviours.foreach(behaviour => parseBehaviour(behaviour))
|
behaviours.foreach(behaviour => parseBehaviour(behaviour))
|
||||||
groundTruths.foreach(groundTruth => parseGroundTruth(groundTruth))
|
groundTruths.foreach(groundTruth => parseGroundTruth(groundTruth))
|
||||||
// TODO: insert dummy sensors if none exists at cells of the parent group where this group exists
|
// TODO: insert dummy sensors if none exists at cells of the parent group where this group exists
|
||||||
// TODO: when inserting time based values, only overwrite None, dont overwrite Some() with None!
|
// TODO: when inserting time based values, only overwrite None, dont overwrite Some() with None!
|
||||||
// e.g. truth was declared at tick 9 with value 11, but later again with None at tick 9, DONT OVERWRITE
|
// e.g. truth was declared at tick 9 with value 11, but later again with None at tick 9, DONT OVERWRITE
|
||||||
// e.g. truth was declared at tick 9 with value none, but later again with value 9, OVERWRITE
|
// e.g. truth was declared at tick 9 with value none, but later again with value 9, OVERWRITE
|
||||||
|
|
||||||
//populate configuration
|
//populate configuration
|
||||||
val configurationMapping = sensorList.map(cell => cell._1 -> cellMapper(cell._1, cell._2.toMap)).toMap
|
val configurationMapping = sensorList.map(cell => cell._1 -> cellMapper(cell._1, cell._2.toMap)).toMap
|
||||||
|
|
||||||
// construct shared memory sensor
|
// construct shared memory sensor
|
||||||
val sharedMemorySensor = Vector.tabulate(config.duration)(t => (Time(t, config.duration), sensorList.map(kv => kv._1 -> kv._2.map(kv2 => kv2._1 -> Vector.tabulate(kv2._2.count)(_ => SensorResult())).toMap).toMap))
|
val sharedMemorySensor = Vector.tabulate(config.getDuration)(t => (Time(t, config.getDuration), sensorList.map(kv => kv._1 -> kv._2.map(kv2 => kv2._1 -> Vector.tabulate(kv2._2.count)(_ => SensorResult())).toMap).toMap))
|
||||||
|
|
||||||
def truthHelper(cell: Cell, list: Map[Group, List[(Group, Sensor, Option[GroundTruth])]]): (Cell, Map[Group, Truth]) = {
|
def truthHelper(cell: Cell, list: Map[Group, List[(Group, Sensor, Option[GroundTruth])]]): (Cell, Map[Group, Truth]) = {
|
||||||
val groupList: mutable.Map[Group, Truth] = mutable.Map()
|
val groupList: mutable.Map[Group, Truth] = mutable.Map()
|
||||||
list.foreach(kv => kv._2.foreach(e => groupList(e._1) = Truth()))
|
list.foreach(kv => kv._2.foreach(e => groupList(e._1) = Truth()))
|
||||||
cell -> groupList.toMap
|
cell -> groupList.toMap
|
||||||
}
|
}
|
||||||
|
|
||||||
val sharedMemoryTruth = Vector.tabulate(config.duration)(t => (Time(t, config.duration), configurationMapping.map(a => truthHelper(a._1, a._2))))
|
val sharedMemoryTruth = Vector.tabulate(config.getDuration)(t => (Time(t, config.getDuration), configurationMapping.map(a => truthHelper(a._1, a._2))))
|
||||||
|
|
||||||
val sharedMemorySensorMap = traversableToMap[Time, Map[Cell, Map[Group, Vector[SensorResult]]]](sharedMemorySensor)
|
val sharedMemorySensorMap = traversableToMap[Time, Map[Cell, Map[Group, Vector[SensorResult]]]](sharedMemorySensor)
|
||||||
|
|
||||||
val sharedMemoryTruthMap = traversableToMap[Time, Map[Cell, Map[Group, Truth]]](sharedMemoryTruth)
|
val sharedMemoryTruthMap = traversableToMap[Time, Map[Cell, Map[Group, Truth]]](sharedMemoryTruth)
|
||||||
|
|
||||||
val sharedMemory = SharedMemory(sharedMemorySensorMap, sharedMemoryTruthMap, groundTruthValues.map(kv => kv._1 -> kv._2.toMap).toMap, config, groups.toMap)
|
val sharedMemory = SharedMemory(sharedMemorySensorMap, sharedMemoryTruthMap, groundTruthValues.map(kv => kv._1 -> kv._2.toMap).toMap, config, groups.toMap)
|
||||||
|
|
||||||
Configuration(configurationMapping, sharedMemory)
|
Configuration(configurationMapping, sharedMemory)
|
||||||
}
|
}
|
||||||
|
|
||||||
private def parseSimulationConfig(configInput: Map[String, Any]): SimulationConfig = {
|
private def parseSimulationConfig(configInput: Map[String, Any]): SimulationConfig = {
|
||||||
val config = configInput.asInstanceOf[Map[String, Int]]
|
val config = configInput.asInstanceOf[Map[String, Int]]
|
||||||
val duration = config("duration")
|
val duration = config("duration")
|
||||||
val runs = config("runs")
|
val runs = config("runs")
|
||||||
val tickfactor = if(config.contains("tickfactor")) config("tickfactor") else 1
|
val tickfactor = if(config.contains("tickfactor")) config("tickfactor") else 1
|
||||||
val parCell = if(config.contains("parCell")) config("parCell") else 0
|
val parCell = if(config.contains("parCell")) config("parCell") else 0
|
||||||
val parCellThreads = if(config.contains("parCellThreads")) config("parCellThreads") else 5
|
val parCellThreads = if(config.contains("parCellThreads")) config("parCellThreads") else 5
|
||||||
val parGroup = if(config.contains("parGroup")) config("parGroup") else 0
|
val parGroup = if(config.contains("parGroup")) config("parGroup") else 0
|
||||||
val parGroupThreads = if(config.contains("parGroupThreads")) config("parGroupThreads") else 5
|
val parGroupThreads = if(config.contains("parGroupThreads")) config("parGroupThreads") else 5
|
||||||
val parSensor = if(config.contains("parSensor")) config("parSensor") else 0
|
val parSensor = if(config.contains("parSensor")) config("parSensor") else 0
|
||||||
val parSensorThreads = if(config.contains("parSensorThreads")) config("parSensorThreads") else 5
|
val parSensorThreads = if(config.contains("parSensorThreads")) config("parSensorThreads") else 5
|
||||||
SimulationConfig(duration, runs, tickfactor, parCell, parCellThreads, parGroup, parGroupThreads, parSensor, parSensorThreads)
|
SimulationConfig(duration, runs, tickfactor, parCell, parCellThreads, parGroup, parGroupThreads, parSensor, parSensorThreads)
|
||||||
}
|
}
|
||||||
|
|
||||||
private def parseSensor(sensor: Map[String, Any]): Unit = {
|
private def parseSensor(sensor: Map[String, Any]): Unit = {
|
||||||
val groupString = sensor("group").asInstanceOf[String]
|
val groupString = sensor("group").asInstanceOf[String]
|
||||||
val parentString: Option[String] = if(sensor.contains("parent")) Some(sensor("parent").asInstanceOf[String]) else None
|
val parentString: Option[String] = if(sensor.contains("parent")) Some(sensor("parent").asInstanceOf[String]) else None
|
||||||
val cells: Map[Cell, SensorCount] = parseCells(sensor("cells").asInstanceOf[Vector[Any]])
|
val cellsParsed: Map[Cell, SensorCount] = if(sensor.contains("cells")) parseCells(sensor("cells").asInstanceOf[Vector[Any]]) else Map()
|
||||||
val group = Group(groupString, parentString)
|
val blocksParsed: Map[Cell, SensorCount] = if(sensor.contains("blocks")) parseBlocks(sensor("blocks").asInstanceOf[Vector[Any]]) else Map()
|
||||||
if(!groups.contains(groupString)) {
|
val cells = mergeMaps[Cell, SensorCount](blocksParsed, cellsParsed, (a: SensorCount, b: SensorCount) => a.add(b), SensorCount(0))
|
||||||
groups(groupString) = group
|
val group = Group(groupString, parentString)
|
||||||
cells.foreach(kv => {
|
if(!groups.contains(groupString)) {
|
||||||
val cell = kv._1
|
groups(groupString) = group
|
||||||
val count = kv._2
|
cells.foreach(kv => {
|
||||||
if(sensorList.contains(cell)) {
|
val cell = kv._1
|
||||||
if(sensorList(cell).contains(group)) {
|
val count = kv._2
|
||||||
// just add sensor count if one was already defined
|
if(sensorList.contains(cell)) {
|
||||||
sensorList(cell)(group) = sensorList(cell)(group).add(count)
|
if(sensorList(cell).contains(group)) {
|
||||||
} else {
|
// just add sensor count if one was already defined
|
||||||
sensorList(cell)(group) = count
|
sensorList(cell)(group) = sensorList(cell)(group).add(count)
|
||||||
}
|
} else {
|
||||||
} else {
|
sensorList(cell)(group) = count
|
||||||
sensorList(cell) = mutable.Map(group -> count)
|
}
|
||||||
}
|
} else {
|
||||||
})
|
sensorList(cell) = mutable.Map(group -> count)
|
||||||
} else {
|
}
|
||||||
debugf(DebugType.WARNING, "Duplicate Sensors in Group [%s]. Ignoring Sensor: %s", groupString, sensor.toString())
|
})
|
||||||
}
|
} else {
|
||||||
}
|
debugf(DebugType.WARNING, "Duplicate Sensors in Group [%s]. Ignoring Sensor: %s", groupString, sensor.toString())
|
||||||
|
}
|
||||||
private def parseCells(cells: Vector[Any]): Map[Cell, SensorCount] = {
|
}
|
||||||
val parseCell: Any => (Cell, SensorCount) = (cell: Any) => cell match {
|
|
||||||
case cell: Vector[_] => val cellVector = cell.asInstanceOf[Vector[Int]]
|
private def parseCells(cells: Vector[Any]): Map[Cell, SensorCount] = {
|
||||||
(Cell(cellVector(0), cellVector(1)), SensorCount(cellVector(2)))
|
val parseCell: Any => (Cell, SensorCount) = (inCell: Any) => inCell match {
|
||||||
case cell: Map[_, _] => val cellMap = cell.asInstanceOf[Map[String, Int]]
|
case cell: Vector[_] => val cellVector = cell.asInstanceOf[Vector[Int]]
|
||||||
(Cell(cellMap("x"), cellMap("y")), SensorCount(cellMap("count")))
|
(Cell(cellVector(0), cellVector(1)), SensorCount(cellVector(2)))
|
||||||
case _ => throw new Exception("Invalid Cell: " + cell.toString)
|
case cell: Map[_, _] => val cellMap = cell.asInstanceOf[Map[String, Int]]
|
||||||
}
|
(Cell(cellMap("x"), cellMap("y")), SensorCount(cellMap("count")))
|
||||||
// traversableToMap iterates over the vector while parseCell returns a key value
|
case _ => throw new Exception("Invalid Cell: " + inCell.toString)
|
||||||
// pair for each element which than gets added to the returned map
|
}
|
||||||
traversableToMap[Cell, SensorCount](cells, parseCell)
|
// traversableToMap iterates over the vector while parseCell returns a key value
|
||||||
}
|
// pair for each element which than gets added to the returned map
|
||||||
|
traversableToMap[Cell, SensorCount](cells, parseCell)
|
||||||
// TODO: multiply time by tickfactor
|
}
|
||||||
private def parseTimeLineElement(timeLineElement: Any): (Int, Option[Int]) = {
|
|
||||||
timeLineElement match {
|
private def parseBlocks(blocks: Vector[Any]): Map[Cell, SensorCount] = {
|
||||||
case timeLineElement: Vector[_] => val elementVector = timeLineElement.asInstanceOf[Vector[Int]]
|
val parseBlock: Any => Map[Cell, SensorCount] = (inBlock: Any) => inBlock match {
|
||||||
(elementVector(0), if(elementVector.size > 1) Some(elementVector(1)) else None)
|
case block: Map[_, _] => {
|
||||||
case timeLineElement: Map[_, _] => val elementMap = timeLineElement.asInstanceOf[Map[String, Int]]
|
val blockMap = block.asInstanceOf[Map[String, Any]]
|
||||||
(elementMap("start"), if(elementMap.contains("end")) Some(elementMap("end")) else None)
|
val start = blockMap("start").asInstanceOf[Vector[Int]]
|
||||||
}
|
val end = blockMap("end").asInstanceOf[Vector[Int]]
|
||||||
}
|
val count = blockMap("count").asInstanceOf[Int]
|
||||||
|
val blockCells = Cell(start(0), start(1)).block(Cell(end(0), end(1)))
|
||||||
private def parseFunction(functions: Vector[Any]): Behaviour = {
|
val countPerCell: Int = count / blockCells.length
|
||||||
val parseFunctionHelper = (function: Any) => {
|
var countRest: Int = count % blockCells.length
|
||||||
var funcPointer: Option[(SimulationBehaviour, Option[FunctionArgs])] = None
|
// TODO: filter out empty cells and return early if countPerCell == 0
|
||||||
function match {
|
val result: Vector[(Cell, SensorCount)] = blockCells.map(cell => {
|
||||||
case function: Vector[_] => {
|
val sensorCount = SensorCount(countPerCell + (if(countRest > 0) 1 else 0))
|
||||||
val start: Int = function(0).asInstanceOf[Int]
|
if(countRest > 0) countRest -= 1
|
||||||
// val end: Option[Int] = None // Not used
|
cell -> sensorCount
|
||||||
val name: String = function(1).asInstanceOf[String]
|
})
|
||||||
val args: Option[FunctionArgs] = if (function.size > 2) Some(FunctionArgs(function(2).asInstanceOf[Map[String, Any]])) else None
|
result.toMap
|
||||||
if (!simulationBehaviours.get(name).isEmpty) funcPointer = Some((simulationBehaviours.get(name).get, args))
|
}
|
||||||
Map[Int, Option[(SimulationBehaviour, Option[FunctionArgs])]](start -> funcPointer) // using a map here since the second case can produces multiple keys
|
case _ => throw new Exception("Invalid Block: " + inBlock.toString)
|
||||||
}
|
}
|
||||||
case function: Map[_, _] => {
|
mergeMaps[Cell, SensorCount](blocks.map(parseBlock), (a: SensorCount, b: SensorCount) => a.add(b), SensorCount(0))
|
||||||
val functionMap = function.asInstanceOf[Map[String, Any]]
|
}
|
||||||
val timeline: Vector[Any] = functionMap("timeline").asInstanceOf[Vector[Any]]
|
|
||||||
val timeLineVector: Vector[(Int, Option[Int])] = timeline.map(e => parseTimeLineElement(e))
|
// don't add tickfacor here, this is done in parseTruth with config.time() and parseFunction with config.tickfactor
|
||||||
val name: String = functionMap("name").asInstanceOf[String]
|
private def parseTimeLineElement(timeLineElement: Any): (Int, Option[Int]) = {
|
||||||
val args: Option[FunctionArgs] = if (functionMap.contains("args")) Some(FunctionArgs(functionMap("args").asInstanceOf[Map[String, Any]])) else None
|
timeLineElement match {
|
||||||
if (!simulationBehaviours.get(name).isEmpty) funcPointer = Some((simulationBehaviours.get(name).get, args))
|
case timeLineElement: Vector[_] => val elementVector = timeLineElement.asInstanceOf[Vector[Int]]
|
||||||
val output: mutable.Map[Int, Option[(SimulationBehaviour, Option[FunctionArgs])]] = mutable.Map()
|
(elementVector(0), if(elementVector.size > 1) Some(elementVector(1)) else None)
|
||||||
timeLineVector.map(tuple => {
|
case timeLineElement: Map[_, _] => val elementMap = timeLineElement.asInstanceOf[Map[String, Int]]
|
||||||
output(tuple._1) = funcPointer
|
(elementMap("start"), if(elementMap.contains("end")) Some(elementMap("end")) else None)
|
||||||
if (!tuple._2.isEmpty && !output.contains(tuple._2.get)) output(tuple._2.get) = None // only set None when it doesnt exist yet
|
}
|
||||||
})
|
}
|
||||||
output.toMap
|
|
||||||
}
|
private def parseFunction(functions: Vector[Any]): Behaviour = {
|
||||||
case _ => throw new Exception("Invalid Function: " + function.toString)
|
val parseFunctionHelper = (function: Any) => {
|
||||||
}
|
var funcPointer: Option[(SimulationBehaviour, Option[FunctionArgs])] = None
|
||||||
}
|
function match {
|
||||||
val parsedFunction: mutable.Map[Int, Option[(SimulationBehaviour, Option[FunctionArgs])]] = mutable.Map().empty
|
case function: Vector[_] => {
|
||||||
// TODO: This will currently overwrite already assigned values; output warning
|
val start: Int = function(0).asInstanceOf[Int] * config.tickfactor
|
||||||
val a = functions.map(function => parseFunctionHelper(function))
|
// val end: Option[Int] = None // Not used
|
||||||
a.foreach(e => e.foreach(kv => {
|
val name: String = function(1).asInstanceOf[String]
|
||||||
if(!kv._2.isEmpty || !parsedFunction.contains(kv._1)) // only set None when it doesnt exist yet
|
val args: Option[FunctionArgs] = if (function.size > 2) Some(FunctionArgs(function(2).asInstanceOf[Map[String, Any]])) else None
|
||||||
parsedFunction(kv._1) = kv._2
|
if (!simulationBehaviours.get(name).isEmpty) funcPointer = Some((simulationBehaviours.get(name).get, args))
|
||||||
} ))
|
Map[Int, Option[(SimulationBehaviour, Option[FunctionArgs])]](start -> funcPointer) // using a map here since the second case can produces multiple keys
|
||||||
val timeVector: mutable.ArraySeq[Option[(SimulationBehaviour, Option[FunctionArgs])]] = new mutable.ArraySeq[Option[(SimulationBehaviour, Option[FunctionArgs])]](config.duration).map(_ => None)
|
}
|
||||||
val it = parsedFunction.toList.sortBy(_._1).iterator
|
case function: Map[_, _] => {
|
||||||
var current = if(it.hasNext) Some(it.next) else None
|
val functionMap = function.asInstanceOf[Map[String, Any]]
|
||||||
while(!current.isEmpty) {
|
val timeline: Vector[Any] = functionMap("timeline").asInstanceOf[Vector[Any]]
|
||||||
val next = if(it.hasNext) Some(it.next) else None
|
val timeLineVector: Vector[(Int, Option[Int])] = timeline.map(e => parseTimeLineElement(e))
|
||||||
for(time <- current.get._1 to (if(!next.isEmpty && next.get._1 < config.duration) next.get._1 else config.duration - 1)) {
|
val name: String = functionMap("name").asInstanceOf[String]
|
||||||
timeVector(time) = current.get._2
|
val args: Option[FunctionArgs] = if (functionMap.contains("args")) Some(FunctionArgs(functionMap("args").asInstanceOf[Map[String, Any]])) else None
|
||||||
}
|
if (!simulationBehaviours.get(name).isEmpty) funcPointer = Some((simulationBehaviours.get(name).get, args))
|
||||||
current = next
|
val output: mutable.Map[Int, Option[(SimulationBehaviour, Option[FunctionArgs])]] = mutable.Map()
|
||||||
}
|
timeLineVector.map(tuple => {
|
||||||
Behaviour(BehaviourVector(timeVector.toVector))
|
output(tuple._1 * config.tickfactor) = funcPointer
|
||||||
}
|
if (!tuple._2.isEmpty && !output.contains(tuple._2.get)) output(tuple._2.get * config.tickfactor) = None // only set None when it doesnt exist yet
|
||||||
|
})
|
||||||
private def parseBehaviour(behaviourMap: Map[String, Any]): Unit = {
|
output.toMap
|
||||||
val groupString = behaviourMap("group").asInstanceOf[String]
|
}
|
||||||
// only continue parsing if sensors in this group exist
|
case _ => throw new Exception("Invalid Function: " + function.toString)
|
||||||
if(groups.contains(groupString)) {
|
}
|
||||||
val group: Group = groups(groupString)
|
}
|
||||||
if(!behaviourListSensor.contains(group)) {
|
val parsedFunction: mutable.Map[Int, Option[(SimulationBehaviour, Option[FunctionArgs])]] = mutable.Map().empty
|
||||||
behaviourListSensor(group) = parseFunction(behaviourMap("functions").asInstanceOf[Vector[Any]])
|
// TODO: This will currently overwrite already assigned values; output warning
|
||||||
} else {
|
val a = functions.map(function => parseFunctionHelper(function))
|
||||||
debugf(DebugType.WARNING, "Duplicate Sensor Behaviour in Group [%s]. Ignoring Behaviour: %s", groupString, behaviourMap.toString())
|
a.foreach(e => e.foreach(kv => {
|
||||||
}
|
if(!kv._2.isEmpty || !parsedFunction.contains(kv._1)) // only set None when it doesnt exist yet
|
||||||
} else {
|
parsedFunction(kv._1) = kv._2
|
||||||
debugf(DebugType.WARNING, "Unused Sensor Behaviour, no sensor for group [%s] exists. Ignoring Behaviour: %s", groupString, behaviourMap.toString())
|
} ))
|
||||||
}
|
val timeVector: mutable.ArraySeq[Option[(SimulationBehaviour, Option[FunctionArgs])]] = new mutable.ArraySeq[Option[(SimulationBehaviour, Option[FunctionArgs])]](config.getDuration).map(_ => None)
|
||||||
}
|
val it = parsedFunction.toList.sortBy(_._1).iterator
|
||||||
|
var current = if(it.hasNext) Some(it.next) else None
|
||||||
private def parseGroundTruth(groundTruthMap: Map[String, Any]): Unit = {
|
while(!current.isEmpty) {
|
||||||
val groupString = groundTruthMap("group").asInstanceOf[String]
|
val next = if(it.hasNext) Some(it.next) else None
|
||||||
// only continue parsing if sensors in this group exist
|
for(time <- current.get._1 to (if(!next.isEmpty && next.get._1 < config.getDuration) next.get._1 else config.getDuration - 1)) {
|
||||||
if(groups.contains(groupString)) {
|
timeVector(time) = current.get._2
|
||||||
val group: Group = groups(groupString)
|
}
|
||||||
if(group.parent.isEmpty) {
|
current = next
|
||||||
if(!behaviourListGroundTruth.contains(group)) {
|
}
|
||||||
group.parent = if(groundTruthMap.contains("parent")) Some(groundTruthMap("parent").asInstanceOf[String]) else None
|
Behaviour(BehaviourVector(timeVector.toVector))
|
||||||
behaviourListGroundTruth(group) = parseFunction(groundTruthMap("delta").asInstanceOf[Vector[Any]])
|
}
|
||||||
} else {
|
|
||||||
debugf(DebugType.WARNING, "Duplicate Ground Truth in Group [%s]. Ignoring Ground Truth: %s", groupString, groundTruthMap.toString())
|
private def parseBehaviour(behaviourMap: Map[String, Any]): Unit = {
|
||||||
}
|
val groupString = behaviourMap("group").asInstanceOf[String]
|
||||||
if(groundTruthMap.contains("truth")){
|
// only continue parsing if sensors in this group exist
|
||||||
parseTruth(groundTruthMap("truth").asInstanceOf[Vector[Any]]).map(kv => {
|
if(groups.contains(groupString)) {
|
||||||
if(groundTruthValues.contains(kv._1)) {
|
val group: Group = groups(groupString)
|
||||||
groundTruthValues(kv._1)(group) = kv._2
|
if(!behaviourListSensor.contains(group)) {
|
||||||
} else {
|
behaviourListSensor(group) = parseFunction(behaviourMap("functions").asInstanceOf[Vector[Any]])
|
||||||
groundTruthValues(kv._1) = mutable.Map[Group, Truth](group -> kv._2)
|
} else {
|
||||||
}
|
debugf(DebugType.WARNING, "Duplicate Sensor Behaviour in Group [%s]. Ignoring Behaviour: %s", groupString, behaviourMap.toString())
|
||||||
})
|
}
|
||||||
} else if(group.parent.isEmpty) {
|
} else {
|
||||||
debugf(DebugType.WARNING, "Sensor Group [%s] has no parent and no ground truth values", groupString)
|
debugf(DebugType.WARNING, "Unused Sensor Behaviour, no sensor for group [%s] exists. Ignoring Behaviour: %s", groupString, behaviourMap.toString())
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
debugf(DebugType.WARNING, "Unused Ground Truth in Group [%s] because the Sensor has Parent [%s]. Ignoring Ground Truth: %s", groupString, group.parent.get, groundTruthMap.toString())
|
|
||||||
}
|
private def parseGroundTruth(groundTruthMap: Map[String, Any]): Unit = {
|
||||||
} else {
|
val groupString = groundTruthMap("group").asInstanceOf[String]
|
||||||
debugf(DebugType.WARNING, "Unused Ground Truth, no sensor for group [%s] exists. Ignoring Ground Truth: %s", groupString, groundTruthMap.toString())
|
// only continue parsing if sensors in this group exist
|
||||||
}
|
if(groups.contains(groupString)) {
|
||||||
}
|
val group: Group = groups(groupString)
|
||||||
|
if(group.parent.isEmpty) {
|
||||||
private def getParentRoot(group: Group, groups: Map[String, Group], seen: Vector[String] = Vector()): Option[Group] = {
|
if(!behaviourListGroundTruth.contains(group)) {
|
||||||
if(seen.contains(group.name)) {
|
group.parent = if(groundTruthMap.contains("parent")) Some(groundTruthMap("parent").asInstanceOf[String]) else None
|
||||||
debugf(DebugType.WARNING, "Circular dependency of groups: [%s]", seen.toString())
|
behaviourListGroundTruth(group) = parseFunction(groundTruthMap("delta").asInstanceOf[Vector[Any]])
|
||||||
None
|
} else {
|
||||||
} else if(!groups.contains(group.name)) { // this should not happen and be caught earlier
|
debugf(DebugType.WARNING, "Duplicate Ground Truth in Group [%s]. Ignoring Ground Truth: %s", groupString, groundTruthMap.toString())
|
||||||
debugf(DebugType.WARNING, "Group [%s] ignored, it is not part of the sensor groups [%s]", group.toString, groups.toString())
|
}
|
||||||
None
|
if(groundTruthMap.contains("truth")){
|
||||||
} else {
|
parseTruth(groundTruthMap("truth").asInstanceOf[Vector[Any]]).map(kv => {
|
||||||
if(group.parent.isEmpty) Some(group) else getParentRoot(groups(group.parent.get), groups, seen ++ Vector(group.name))
|
if(groundTruthValues.contains(kv._1)) {
|
||||||
}
|
groundTruthValues(kv._1)(group) = kv._2
|
||||||
}
|
} else {
|
||||||
|
groundTruthValues(kv._1) = mutable.Map[Group, Truth](group -> kv._2)
|
||||||
private def parseTruth(truthElements: Vector[Any]): Map[Time, Truth] = {
|
}
|
||||||
val parseTruthHelper = (truthElement: Any) => {
|
})
|
||||||
truthElement match {
|
} else if(group.parent.isEmpty) {
|
||||||
case truthObject: Vector[_] => {
|
debugf(DebugType.WARNING, "Sensor Group [%s] has no parent and no ground truth values", groupString)
|
||||||
val truth: Truth = Truth()
|
}
|
||||||
val start: Int = truthObject(0).asInstanceOf[Int]
|
} else {
|
||||||
// val end: Option[Int] = None // Not used
|
debugf(DebugType.WARNING, "Unused Ground Truth in Group [%s] because the Sensor has Parent [%s]. Ignoring Ground Truth: %s", groupString, group.parent.get, groundTruthMap.toString())
|
||||||
truth.set(parseDouble(truthObject(1)))
|
}
|
||||||
Map[Time, Truth](Time(start, config.duration) -> truth)
|
} else {
|
||||||
}
|
debugf(DebugType.WARNING, "Unused Ground Truth, no sensor for group [%s] exists. Ignoring Ground Truth: %s", groupString, groundTruthMap.toString())
|
||||||
case truthObject: Map[_, _] => {
|
}
|
||||||
val truth: Truth = Truth()
|
}
|
||||||
lazy val endTruth: Truth = Truth()
|
|
||||||
val truthObjectMap = truthObject.asInstanceOf[Map[String, Any]]
|
private def getParentRoot(group: Group, groups: Map[String, Group], seen: Vector[String] = Vector()): Option[Group] = {
|
||||||
val timeline: Vector[Any] = truthObjectMap("timeline").asInstanceOf[Vector[Any]]
|
if(seen.contains(group.name)) {
|
||||||
val timeLineVector: Vector[(Int, Option[Int])] = timeline.map(e => parseTimeLineElement(e))
|
debugf(DebugType.WARNING, "Circular dependency of groups: [%s]", seen.toString())
|
||||||
truth.set(parseDouble(truthObjectMap("value")))
|
None
|
||||||
|
} else if(!groups.contains(group.name)) { // this should not happen and be caught earlier
|
||||||
val output: mutable.Map[Time, Truth] = mutable.Map()
|
debugf(DebugType.WARNING, "Group [%s] ignored, it is not part of the sensor groups [%s]", group.toString, groups.toString())
|
||||||
timeLineVector.map(tuple => {
|
None
|
||||||
output(Time(tuple._1, config.duration)) = truth
|
} else {
|
||||||
if (!tuple._2.isEmpty) {
|
if(group.parent.isEmpty) Some(group) else getParentRoot(groups(group.parent.get), groups, seen ++ Vector(group.name))
|
||||||
endTruth.set(None)
|
}
|
||||||
output(Time(tuple._2.get, config.duration)) = endTruth
|
}
|
||||||
}
|
|
||||||
})
|
private def parseTruth(truthElements: Vector[Any]): Map[Time, Truth] = {
|
||||||
output.toMap
|
val parseTruthHelper = (truthElement: Any) => {
|
||||||
}
|
truthElement match {
|
||||||
case _ => throw new Exception("Invalid Truth: " + truthElement.toString)
|
case truthObject: Vector[_] => {
|
||||||
}
|
val truth: Truth = Truth()
|
||||||
}
|
val start: Int = truthObject(0).asInstanceOf[Int]
|
||||||
val parsedTruth: mutable.Map[Time,Truth] = mutable.Map().empty
|
// val end: Option[Int] = None // Not used
|
||||||
// TODO: This will currently overwrite already assigned values; output warning
|
truth.set(parseDouble(truthObject(1)))
|
||||||
truthElements.map(truth => parseTruthHelper(truth)).foreach(e => e.foreach(kv => parsedTruth(kv._1) = kv._2))
|
Map[Time, Truth](config.time(start) -> truth)
|
||||||
parsedTruth.toMap
|
}
|
||||||
}
|
case truthObject: Map[_, _] => {
|
||||||
|
val truth: Truth = Truth()
|
||||||
def cellMapper(cell: Cell, groups: Map[Group, SensorCount]): Map[Group, List[(Group, Sensor, Option[GroundTruth])]] = {
|
lazy val endTruth: Truth = Truth()
|
||||||
val groupMap: mutable.Map[Group, List[(Group, Sensor, Option[GroundTruth])]] = mutable.Map()
|
val truthObjectMap = truthObject.asInstanceOf[Map[String, Any]]
|
||||||
val groupDone: mutable.HashSet[Group] = mutable.HashSet()
|
val timeline: Vector[Any] = truthObjectMap("timeline").asInstanceOf[Vector[Any]]
|
||||||
|
val timeLineVector: Vector[(Int, Option[Int])] = timeline.map(e => parseTimeLineElement(e))
|
||||||
def groupMapper(group: Group, count: SensorCount): List[(Group, Sensor, Option[GroundTruth])] = {
|
truth.set(parseDouble(truthObjectMap("value")))
|
||||||
if(groupDone.contains(group)) {
|
|
||||||
// if we've already seen the group, get the list so we can add a depended group
|
val output: mutable.Map[Time, Truth] = mutable.Map()
|
||||||
val root = getParentRoot(group, this.groups.toMap) // get root if already added
|
timeLineVector.map(tuple => {
|
||||||
if(!root.isEmpty) {
|
output(config.time(tuple._1)) = truth
|
||||||
groupMap(root.get)
|
if (!tuple._2.isEmpty) {
|
||||||
} else { List() } // circular dependency, just return empty list
|
endTruth.set(None)
|
||||||
} else {
|
output(config.time(tuple._2.get)) = endTruth
|
||||||
if(!behaviourListSensor.contains(group)) {
|
}
|
||||||
debugf(DebugType.WARNING, "Group [%s] does not have a behaviour, using default", group.toString())
|
})
|
||||||
behaviourListSensor(group) = Behaviour(BehaviourVector(Vector.tabulate(config.duration)(_ => None)))
|
output.toMap
|
||||||
}
|
}
|
||||||
if(group.parent.isEmpty) {
|
case _ => throw new Exception("Invalid Truth: " + truthElement.toString)
|
||||||
groupDone.add(group)
|
}
|
||||||
List((group, Sensor(group, cell, count, behaviourListSensor(group), config.parSensor, config.sensorThreadPool),
|
}
|
||||||
if(behaviourListGroundTruth.contains(group)) Some(GroundTruth(group, Some(behaviourListGroundTruth(group)))) else None))
|
val parsedTruth: mutable.Map[Time,Truth] = mutable.Map().empty
|
||||||
} else {
|
// TODO: This will currently overwrite already assigned values; output warning
|
||||||
groupDone.add(group)
|
truthElements.map(truth => parseTruthHelper(truth)).foreach(e => e.foreach(kv => parsedTruth(kv._1) = kv._2))
|
||||||
val parentGroup = this.groups(group.parent.get) // this should really exist at this point
|
parsedTruth.toMap
|
||||||
val parentCount = if(groups.contains(parentGroup)) groups(parentGroup) else SensorCount(0) // insert dummy parent group if not in cell
|
}
|
||||||
groupMapper(parentGroup, parentCount) ++ List((group, Sensor(group, cell, count, behaviourListSensor(group), config.parSensor, config.sensorThreadPool),
|
|
||||||
if(behaviourListGroundTruth.contains(group)) Some(GroundTruth(group, Some(behaviourListGroundTruth(group)))) else None))
|
def cellMapper(cell: Cell, groups: Map[Group, SensorCount]): Map[Group, List[(Group, Sensor, Option[GroundTruth])]] = {
|
||||||
}
|
val groupMap: mutable.Map[Group, List[(Group, Sensor, Option[GroundTruth])]] = mutable.Map()
|
||||||
}
|
val groupDone: mutable.HashSet[Group] = mutable.HashSet()
|
||||||
}
|
|
||||||
|
def groupMapper(group: Group, count: SensorCount): List[(Group, Sensor, Option[GroundTruth])] = {
|
||||||
groups.foreach(kv => {
|
if(groupDone.contains(group)) {
|
||||||
val group = kv._1
|
// if we've already seen the group, get the list so we can add a depended group
|
||||||
val count = kv._2
|
val root = getParentRoot(group, this.groups.toMap) // get root if already added
|
||||||
val root = getParentRoot(group, this.groups.toMap)
|
if(!root.isEmpty) {
|
||||||
if(!groupDone.contains(group) && !root.isEmpty) {
|
groupMap(root.get)
|
||||||
groupMap(root.get) = groupMapper(group, count)
|
} else { List() } // circular dependency, just return empty list
|
||||||
}
|
} else {
|
||||||
})
|
if(!behaviourListSensor.contains(group)) {
|
||||||
groupMap.toMap
|
debugf(DebugType.WARNING, "Group [%s] does not have a behaviour, using default", group.toString())
|
||||||
}
|
behaviourListSensor(group) = Behaviour(BehaviourVector(Vector.tabulate(config.getDuration)(_ => None)))
|
||||||
|
}
|
||||||
|
if(group.parent.isEmpty) {
|
||||||
|
groupDone.add(group)
|
||||||
|
List((group, Sensor(group, cell, count, behaviourListSensor(group), config.parSensor, config.sensorThreadPool),
|
||||||
|
if(behaviourListGroundTruth.contains(group)) Some(GroundTruth(group, Some(behaviourListGroundTruth(group)))) else None))
|
||||||
|
} else {
|
||||||
|
groupDone.add(group)
|
||||||
|
val parentGroup = this.groups(group.parent.get) // this should really exist at this point
|
||||||
|
val parentCount = if(groups.contains(parentGroup)) groups(parentGroup) else SensorCount(0) // insert dummy parent group if not in cell
|
||||||
|
groupMapper(parentGroup, parentCount) ++ List((group, Sensor(group, cell, count, behaviourListSensor(group), config.parSensor, config.sensorThreadPool),
|
||||||
|
if(behaviourListGroundTruth.contains(group)) Some(GroundTruth(group, Some(behaviourListGroundTruth(group)))) else None))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
groups.foreach(kv => {
|
||||||
|
val group = kv._1
|
||||||
|
val count = kv._2
|
||||||
|
val root = getParentRoot(group, this.groups.toMap)
|
||||||
|
if(!groupDone.contains(group) && !root.isEmpty) {
|
||||||
|
groupMap(root.get) = groupMapper(group, count)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
groupMap.toMap
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -15,7 +15,7 @@ class Simulation(config: Configuration) {
|
|||||||
|
|
||||||
def start(): Unit = {
|
def start(): Unit = {
|
||||||
val duration = config.getDuration
|
val duration = config.getDuration
|
||||||
val timeVector = Vector.tabulate(duration)(t => Time(t, duration))
|
val timeVector = Vector.tabulate(duration)(t => Time(t, duration, Some(config.getTickFactor)))
|
||||||
def simTime(time: Time): Unit = {
|
def simTime(time: Time): Unit = {
|
||||||
// FIXME: really shouldn't have to .map(kv => kv._1 -> kv._2) to get an immutable map, in fact it shouldn't even be mutable in the first place...
|
// FIXME: really shouldn't have to .map(kv => kv._1 -> kv._2) to get an immutable map, in fact it shouldn't even be mutable in the first place...
|
||||||
val prevTruths: scala.collection.immutable.Map[Cell, Map[Group, Truth]] = if(time.start) sharedMemory.groundTruth(time).map(kv => kv._1 -> kv._2) else sharedMemory.groundTruth(time.prev).map(kv => kv._1 -> kv._2)
|
val prevTruths: scala.collection.immutable.Map[Cell, Map[Group, Truth]] = if(time.start) sharedMemory.groundTruth(time).map(kv => kv._1 -> kv._2) else sharedMemory.groundTruth(time.prev).map(kv => kv._1 -> kv._2)
|
||||||
|
|||||||
@@ -12,15 +12,31 @@ import scala.util.control.NonFatal
|
|||||||
|
|
||||||
// Note: case classes implement equality and compare their values and not the memory address
|
// Note: case classes implement equality and compare their values and not the memory address
|
||||||
// It only compares vals from the constructor
|
// It only compares vals from the constructor
|
||||||
case class Time(time: Int, duration: Int) extends Ordered[Time]{
|
case class Time(time: Int, duration: Int, tickfactor: Option[Int] = None) extends Ordered[Time]{
|
||||||
def prev: Time = { Time(time - 1, duration) }
|
def prev: Time = Time(time - 1, duration, tickfactor)
|
||||||
|
def prevTickfactor = Time(time - 1 * tickfactor.getOrElse(1), duration, tickfactor)
|
||||||
|
def next: Time = Time(time + 1, duration, tickfactor)
|
||||||
|
def nextTickfactor = Time(time + 1 * tickfactor.getOrElse(1), duration, tickfactor)
|
||||||
def start: Boolean = { time == 0 }
|
def start: Boolean = { time == 0 }
|
||||||
def get: Int = { time }
|
def get: Int = { time }
|
||||||
|
def getNormalized: Int = time / tickfactor.getOrElse(1)
|
||||||
|
def getNormalized(collision: Option[Int] = None): Option[Int] = {
|
||||||
|
if((time % tickfactor.getOrElse(1) )== 0) Some(time / tickfactor.getOrElse(1)) else collision
|
||||||
|
}
|
||||||
|
def newTime(t: Int, normalized: Boolean = true): Time = if(normalized) Time(t * tickfactor.getOrElse(1), duration, tickfactor) else Time(t, duration, tickfactor)
|
||||||
|
override def equals(obj: Any): Boolean = {
|
||||||
|
obj match {
|
||||||
|
case that: Time => time.equals(that.time)
|
||||||
|
case that: Int => time.equals(that * tickfactor.getOrElse(1))
|
||||||
|
case _ => false
|
||||||
|
}
|
||||||
|
}
|
||||||
override def compare(that: Time): Int = {
|
override def compare(that: Time): Int = {
|
||||||
time.compare(that.time)
|
time.compare(that.time)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override def hashCode: Int = time.hashCode()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// while it would seem convinient to just throw the sensors/behaviours as value into these
|
// while it would seem convinient to just throw the sensors/behaviours as value into these
|
||||||
@@ -81,6 +97,11 @@ case class SimulationConfig(duration: Int, runs: Int, tickfactor: Int = 1,
|
|||||||
val cellThreadPool: ForkJoinTaskSupport = new ForkJoinTaskSupport(new scala.concurrent.forkjoin.ForkJoinPool(parCellThreads))
|
val cellThreadPool: ForkJoinTaskSupport = new ForkJoinTaskSupport(new scala.concurrent.forkjoin.ForkJoinPool(parCellThreads))
|
||||||
val groupThreadPool: ForkJoinTaskSupport = new ForkJoinTaskSupport(new scala.concurrent.forkjoin.ForkJoinPool(parGroupThreads))
|
val groupThreadPool: ForkJoinTaskSupport = new ForkJoinTaskSupport(new scala.concurrent.forkjoin.ForkJoinPool(parGroupThreads))
|
||||||
val sensorThreadPool: ForkJoinTaskSupport = new ForkJoinTaskSupport(new scala.concurrent.forkjoin.ForkJoinPool(parSensorThreads))
|
val sensorThreadPool: ForkJoinTaskSupport = new ForkJoinTaskSupport(new scala.concurrent.forkjoin.ForkJoinPool(parSensorThreads))
|
||||||
|
def time(t: Int, useTickfactor: Boolean = true): Time = {
|
||||||
|
if (useTickfactor) Time(t * tickfactor, getDuration * tickfactor, Some(tickfactor))
|
||||||
|
else Time(t, getDuration * tickfactor, Some(tickfactor))
|
||||||
|
}
|
||||||
|
def getDuration: Int = duration * tickfactor
|
||||||
}
|
}
|
||||||
case class SensorResult() extends Result[(Group, Cell, Option[Double])]
|
case class SensorResult() extends Result[(Group, Cell, Option[Double])]
|
||||||
/* rough size estimation
|
/* rough size estimation
|
||||||
@@ -105,6 +126,18 @@ case class Cell(x: Int, y: Int) {
|
|||||||
def distance(otherCell: Cell): Double = {
|
def distance(otherCell: Cell): Double = {
|
||||||
Math.sqrt(Math.pow(x - otherCell.x, 2) + Math.pow(y - otherCell.y, 2))
|
Math.sqrt(Math.pow(x - otherCell.x, 2) + Math.pow(y - otherCell.y, 2))
|
||||||
}
|
}
|
||||||
|
def block(otherCell: Cell): Vector[Cell] = {
|
||||||
|
val bottomLeft = Cell(math.min(x, otherCell.x), math.min(y, otherCell.y))
|
||||||
|
val topRight = Cell(math.max(x, otherCell.x), math.max(y, otherCell.y))
|
||||||
|
// add + 1 as topright is included in the block
|
||||||
|
val xCount = topRight.x - bottomLeft.x + 1
|
||||||
|
val yCount = topRight.y - bottomLeft.y + 1
|
||||||
|
Vector.tabulate(yCount)(yCoord => {
|
||||||
|
Vector.tabulate(xCount)(xCoord => {
|
||||||
|
Cell(xCoord + bottomLeft.x, yCoord + bottomLeft.y)
|
||||||
|
})
|
||||||
|
}).flatten
|
||||||
|
}
|
||||||
}
|
}
|
||||||
case class Group(name: String, sensorParent: Option[String] = None){
|
case class Group(name: String, sensorParent: Option[String] = None){
|
||||||
// the sensorParent serves as indicator for the parser that a ground truth is not required
|
// the sensorParent serves as indicator for the parser that a ground truth is not required
|
||||||
@@ -130,7 +163,7 @@ case class FunctionArgs(args: Map[String, Any]) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case class BehaviourVector(function: Vector[Option[(SimulationBehaviour, Option[FunctionArgs])]],
|
case class BehaviourVector(function: Vector[Option[(SimulationBehaviour, Option[FunctionArgs])]],
|
||||||
defaultFunc: SimulationBehaviour = (_: Cell, _: Time, v: Option[Double], _: Option[FunctionArgs]) => v,
|
defaultFunc: SimulationBehaviour = (_: Cell, _: Time, _: Option[Double], _: Option[FunctionArgs]) => None,
|
||||||
defaultArgs: Option[FunctionArgs] = None) {
|
defaultArgs: Option[FunctionArgs] = None) {
|
||||||
def get(t: Time): (SimulationBehaviour, Option[FunctionArgs]) = {
|
def get(t: Time): (SimulationBehaviour, Option[FunctionArgs]) = {
|
||||||
function(t.time).getOrElse((defaultFunc, defaultArgs))
|
function(t.time).getOrElse((defaultFunc, defaultArgs))
|
||||||
@@ -195,7 +228,7 @@ case class SensorCount(count: Int) {
|
|||||||
|
|
||||||
// NOTE: The Group is actually obsolete in the Tuple3 as Sensor and GroundTruth hold theirs (unless removed from their case class)
|
// NOTE: The Group is actually obsolete in the Tuple3 as Sensor and GroundTruth hold theirs (unless removed from their case class)
|
||||||
case class Configuration(cells: Map[Cell, Map[Group, List[(Group, Sensor, Option[GroundTruth])]]], sharedMemory: SharedMemory) extends SimConfig {
|
case class Configuration(cells: Map[Cell, Map[Group, List[(Group, Sensor, Option[GroundTruth])]]], sharedMemory: SharedMemory) extends SimConfig {
|
||||||
def getDuration: Int = sharedMemory.config.duration
|
def getDuration: Int = sharedMemory.config.duration * sharedMemory.config.tickfactor
|
||||||
def getRuns: Int = sharedMemory.config.runs
|
def getRuns: Int = sharedMemory.config.runs
|
||||||
def getTickFactor: Int = sharedMemory.config.tickfactor
|
def getTickFactor: Int = sharedMemory.config.tickfactor
|
||||||
def getCellThreadConfig: (Int, ForkJoinTaskSupport) = (sharedMemory.config.parCell, sharedMemory.config.cellThreadPool)
|
def getCellThreadConfig: (Int, ForkJoinTaskSupport) = (sharedMemory.config.parCell, sharedMemory.config.cellThreadPool)
|
||||||
|
|||||||
@@ -34,6 +34,10 @@ package object configInterfaces {
|
|||||||
def getDuration: Int
|
def getDuration: Int
|
||||||
def getRuns: Int
|
def getRuns: Int
|
||||||
def getTickFactor: Int
|
def getTickFactor: Int
|
||||||
|
def newTime(t: Int, tickfactor: Boolean = true): Time = {
|
||||||
|
if (tickfactor) Time(t * getTickFactor, getDuration * getTickFactor, Some(getTickFactor))
|
||||||
|
else Time(t, getDuration * getTickFactor, Some(getTickFactor))
|
||||||
|
}
|
||||||
def getCellThreadConfig: (Int, ForkJoinTaskSupport)
|
def getCellThreadConfig: (Int, ForkJoinTaskSupport)
|
||||||
def getGroupThreadConfig: (Int, ForkJoinTaskSupport)
|
def getGroupThreadConfig: (Int, ForkJoinTaskSupport)
|
||||||
def getSensorThreadConfig: (Int, ForkJoinTaskSupport)
|
def getSensorThreadConfig: (Int, ForkJoinTaskSupport)
|
||||||
|
|||||||
@@ -152,6 +152,18 @@ package object mapUtil {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def mergeMaps[A, B](mapA: Map[A, B], mapB: Map[A, B], add: (B, B) => B, default: B): Map[A, B] = {
|
||||||
|
mapA ++ mapB.map(e => e._1 -> add(e._2, mapA.getOrElse(e._1, default)))
|
||||||
|
}
|
||||||
|
|
||||||
|
def mergeMaps[A, B](vector: Vector[Map[A, B]], add: (B, B) => B, default: B): Map[A, B] = {
|
||||||
|
if(vector.length > 1) {
|
||||||
|
mergeMaps(vector.head, mergeMaps(vector.tail, add, default), add, default)
|
||||||
|
} else {
|
||||||
|
vector.head
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
def traversableToMap[A, B](traversable: Traversable[Any], getTuple: (Any) => (A, B) = (e: Any) => e.asInstanceOf[(A, B)]._1 -> e.asInstanceOf[(A, B)]._2): Map[A, B] = {
|
def traversableToMap[A, B](traversable: Traversable[Any], getTuple: (Any) => (A, B) = (e: Any) => e.asInstanceOf[(A, B)]._1 -> e.asInstanceOf[(A, B)]._2): Map[A, B] = {
|
||||||
// Traversable[Tuple[A, B]] can be converted via .map
|
// Traversable[Tuple[A, B]] can be converted via .map
|
||||||
// .foldLeft used in favor of .map().toMap as the latter needs two traversals
|
// .foldLeft used in favor of .map().toMap as the latter needs two traversals
|
||||||
@@ -426,4 +438,30 @@ package object parserUtil {
|
|||||||
case _ => None
|
case _ => None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
package object io {
|
||||||
|
import java.io._
|
||||||
|
case class OutputFile(fileName: String = "output.txt", newFile: Boolean = true) {
|
||||||
|
val file = new File(fileName)
|
||||||
|
val buffer: mutable.StringBuilder = new mutable.StringBuilder()
|
||||||
|
|
||||||
|
if(newFile) {
|
||||||
|
val fw = new FileWriter(file)
|
||||||
|
fw.write("")
|
||||||
|
fw.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
def buffer(text: String): Unit = {
|
||||||
|
buffer.append(text)
|
||||||
|
}
|
||||||
|
|
||||||
|
def write(): Unit = {
|
||||||
|
val fwAppend = new FileWriter(file, true)
|
||||||
|
fwAppend.write(buffer.toString())
|
||||||
|
fwAppend.close()
|
||||||
|
buffer.clear()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user