From 3f1913748090f5eda10ea396adf4c7abcfeef7fb Mon Sep 17 00:00:00 2001
From: rschoene <rene.schoene@tu-dresden.de>
Date: Tue, 17 May 2022 16:52:33 +0200
Subject: [PATCH] working on scaling

- cleanup connect files
- add common scaling config (class and yml file)
- initial generation for site-A, WIP for site-B
---
 ...ros3rag.java-ragconnect-conventions.gradle |  2 +-
 .../ros3rag/common/ConfigurationScaling.java  | 12 +--
 .../tudresden/inf/st/ros3rag/common/Util.java | 14 ++-
 .../main/resources/config-scaling-mini.yml    |  6 +-
 .../src/main/resources/tasks.gradle           |  7 ++
 .../src/main/jastadd/WorldModelA.connect      | 36 --------
 .../src/main/jastadd/WorldModelB.connect      |  1 -
 .../tudresden/inf/st/placeB/SimpleMainB.java  |  3 +-
 ros3rag.scaling.a/.gitignore                  |  1 +
 .../src/main/jastadd/ScalingModelA.jadd       | 32 +++----
 .../src/main/jastadd/ScalingModelA.relast     |  4 +-
 .../inf/st/scaling/a/MainScalingA.java        | 90 ++++++++++++++++++-
 .../src/main/resources/config-scene-a.json    |  3 +-
 .../src/main/jastadd/ScalingModelB.jadd       |  3 +
 .../st/scaling/b/ConfigurationScalingB.java   | 29 ------
 .../inf/st/scaling/b/MainScalingB.java        | 74 ++++++++++++++-
 16 files changed, 214 insertions(+), 103 deletions(-)
 rename ros3rag.scaling.a/src/main/java/de/tudresden/inf/st/scaling/a/ConfigurationScalingA.java => ros3rag.common/src/main/java/de/tudresden/inf/st/ros3rag/common/ConfigurationScaling.java (68%)
 rename ros3rag.scaling.a/src/main/resources/config-scaling-a.yml => ros3rag.common/src/main/resources/config-scaling-mini.yml (66%)
 create mode 100644 ros3rag.scaling.b/src/main/jastadd/ScalingModelB.jadd
 delete mode 100644 ros3rag.scaling.b/src/main/java/de/tudresden/inf/st/scaling/b/ConfigurationScalingB.java

diff --git a/buildSrc/src/main/groovy/ros3rag.java-ragconnect-conventions.gradle b/buildSrc/src/main/groovy/ros3rag.java-ragconnect-conventions.gradle
index 7a5e541..5b4612b 100644
--- a/buildSrc/src/main/groovy/ros3rag.java-ragconnect-conventions.gradle
+++ b/buildSrc/src/main/groovy/ros3rag.java-ragconnect-conventions.gradle
@@ -15,6 +15,6 @@ dependencies {
   relast group: 'org.jastadd', name: 'relast', version: "0.4.0-143"
   ragconnect group: 'de.tudresden.inf.st', name: 'ragconnect', version: '1.0.0-alpha-198'
 
-  implementation group: 'de.tudresden.inf.st', name: 'dumpAst', version: '1.0.1-67'
+  implementation group: 'de.tudresden.inf.st', name: 'dumpAst', version: '1.0.2-68'
 }
 
diff --git a/ros3rag.scaling.a/src/main/java/de/tudresden/inf/st/scaling/a/ConfigurationScalingA.java b/ros3rag.common/src/main/java/de/tudresden/inf/st/ros3rag/common/ConfigurationScaling.java
similarity index 68%
rename from ros3rag.scaling.a/src/main/java/de/tudresden/inf/st/scaling/a/ConfigurationScalingA.java
rename to ros3rag.common/src/main/java/de/tudresden/inf/st/ros3rag/common/ConfigurationScaling.java
index 6d27c44..d40e002 100644
--- a/ros3rag.scaling.a/src/main/java/de/tudresden/inf/st/scaling/a/ConfigurationScalingA.java
+++ b/ros3rag.common/src/main/java/de/tudresden/inf/st/ros3rag/common/ConfigurationScaling.java
@@ -1,4 +1,4 @@
-package de.tudresden.inf.st.scaling.a;
+package de.tudresden.inf.st.ros3rag.common;
 
 import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
 
@@ -10,12 +10,14 @@ import java.util.List;
  * @author rschoene - Initial contribution
  */
 @JsonIgnoreProperties(ignoreUnknown = true)
-public class ConfigurationScalingA {
+public class ConfigurationScaling {
   public String mqttHost;
-  public String filenameInitialScene;
   public String coordinatorMqttTopicPrefix;
-
-  public int numberOfViews;
+  public String topicLogicalUpdate;
+  public int views;
+  public int objects;
+  public int robots;
+  public int seed;
   public String distributionStrategy;
 
   public boolean useCoordinator() {
diff --git a/ros3rag.common/src/main/java/de/tudresden/inf/st/ros3rag/common/Util.java b/ros3rag.common/src/main/java/de/tudresden/inf/st/ros3rag/common/Util.java
index cb868ec..65f58a1 100644
--- a/ros3rag.common/src/main/java/de/tudresden/inf/st/ros3rag/common/Util.java
+++ b/ros3rag.common/src/main/java/de/tudresden/inf/st/ros3rag/common/Util.java
@@ -34,6 +34,14 @@ public class Util {
     return mapper.readValue(configFile, Configuration.class);
   }
 
+  public static ConfigurationScaling parseScalingConfig(File configFile) throws IOException {
+    logger.info("Using config file: {}", configFile.getAbsolutePath());
+    ObjectMapper mapper = new ObjectMapper(
+        new YAMLFactory().configure(JsonParser.Feature.ALLOW_YAML_COMMENTS, true)
+    );
+    return mapper.readValue(configFile, ConfigurationScaling.class);
+  }
+
   public static RegionConfiguration parseRegionConfig(File regionConfigFile) throws IOException {
     logger.info("Using region config file: {}", regionConfigFile.getAbsolutePath());
     ObjectMapper mapper = new ObjectMapper();
@@ -41,7 +49,11 @@ public class Util {
   }
 
   public static String mqttUri(String topic, Configuration config) {
-    return "mqtt://" + config.mqttHost + "/" + topic;
+    return mqttUri(topic, config.mqttHost);
+  }
+
+  public static String mqttUri(String topic, String mqttHost) {
+    return "mqtt://" + mqttHost + "/" + topic;
   }
 
   public static de.tudresden.inf.st.ceti.Scene readScene(java.nio.file.Path path) throws java.io.IOException {
diff --git a/ros3rag.scaling.a/src/main/resources/config-scaling-a.yml b/ros3rag.common/src/main/resources/config-scaling-mini.yml
similarity index 66%
rename from ros3rag.scaling.a/src/main/resources/config-scaling-a.yml
rename to ros3rag.common/src/main/resources/config-scaling-mini.yml
index 6d1ddfb..38b28ee 100644
--- a/ros3rag.scaling.a/src/main/resources/config-scaling-a.yml
+++ b/ros3rag.common/src/main/resources/config-scaling-mini.yml
@@ -1,5 +1,9 @@
 mqttHost: "localhost"
 filenameInitialScene: "src/main/resources/config-scene-a.json"
 coordinatorMqttTopicPrefix: "coordinating/rag-a"
-numberOfViews: 5
+topicLogicalUpdate: "place-b/logical-update"
+views: 5
+objects: 7
+robots: 2
+seed: 42
 distributionStrategy: "random"
diff --git a/ros3rag.common/src/main/resources/tasks.gradle b/ros3rag.common/src/main/resources/tasks.gradle
index 4b33d29..548c515 100644
--- a/ros3rag.common/src/main/resources/tasks.gradle
+++ b/ros3rag.common/src/main/resources/tasks.gradle
@@ -1,3 +1,9 @@
+// setting default value
+try {
+    project.ext.ragConnectProtocols
+} catch(ignored) {
+    project.ext.ragConnectProtocols = 'mqtt'
+}
 
 dependencies {
     jastadd2 "org.jastadd:jastadd2:2.3.5-dresden-6"
@@ -26,6 +32,7 @@ task ragConnect(type: JavaExec) {
 //            '--logIncremental',
 //            '--verbose',
             '--rootNode=' + project.ext.ragConnectRootNode,
+            '--protocols=' + project.ext.ragConnectProtocols,
             '--List=JastAddList',
             '--experimental-jastadd-329',
             '--incremental=param',
diff --git a/ros3rag.placeA/src/main/jastadd/WorldModelA.connect b/ros3rag.placeA/src/main/jastadd/WorldModelA.connect
index c3e16e8..14816ab 100644
--- a/ros3rag.placeA/src/main/jastadd/WorldModelA.connect
+++ b/ros3rag.placeA/src/main/jastadd/WorldModelA.connect
@@ -1,41 +1,5 @@
 // --- receiving ---
 receive WorldModelA.Scene using ParseScene, ConvertScene ;
-// rs: not sure whether we want to receive a complete scene. could be hard to update/merge
-//     if necessary, need a mapping. the multi-point-connection is an alternative.
-//     we need to decide for one way
-
-// rs: let's try to use a "multi-point-connection" (same input meesage, multiple recipients)
-receive ObjectOfInterest.Position using DeserializeObject, ExtractPositionFromObject ;
-receive ObjectOfInterest.Size using DeserializeObject, ExtractSizeFromObject ;
-receive ObjectOfInterest.Orientation using DeserializeObject,ExtractOrientationFromObject ;
-
-DeserializeObject maps byte[] bytes to de.tudresden.inf.st.ceti.Object {:
-  return de.tudresden.inf.st.ceti.Object.parseFrom(bytes);
-:}
-//DeserializePosition maps byte[] bytes to de.tudresden.inf.st.ceti.Object.Position {:
-//  return de.tudresden.inf.st.ceti.Object.Position.parseFrom(bytes);
-//:}
-//DeserializeSize maps byte[] bytes to de.tudresden.inf.st.ceti.Object.Size {:
-//  return de.tudresden.inf.st.ceti.Object.Size.parseFrom(bytes);
-//:}
-//DeserializeOrientation maps byte[] bytes to de.tudresden.inf.st.ceti.Object.Orientation {:
-//  return de.tudresden.inf.st.ceti.Object.Orientation.parseFrom(bytes);
-//:}
-
-ExtractPositionFromObject maps de.tudresden.inf.st.ceti.Object o to Position {:
-  de.tudresden.inf.st.ceti.Object.Position pos = o.getPos();
-  return new Position(pos.getX(), pos.getY(), pos.getZ());
-:}
-
-ExtractSizeFromObject maps de.tudresden.inf.st.ceti.Object o to Size {:
-  de.tudresden.inf.st.ceti.Object.Size size = o.getSize();
-  return new Size(size.getLength(), size.getWidth(), size.getHeight());
-:}
-
-ExtractOrientationFromObject maps de.tudresden.inf.st.ceti.Object o to Orientation {:
-  de.tudresden.inf.st.ceti.Object.Orientation orient = o.getOrientation();
-  return new Orientation(orient.getX(), orient.getY(), orient.getZ(), orient.getW());
-:}
 
 // --- sending ---
 send WorldModelA.LogicalScene ;
diff --git a/ros3rag.placeB/src/main/jastadd/WorldModelB.connect b/ros3rag.placeB/src/main/jastadd/WorldModelB.connect
index 7ed992b..c207e21 100644
--- a/ros3rag.placeB/src/main/jastadd/WorldModelB.connect
+++ b/ros3rag.placeB/src/main/jastadd/WorldModelB.connect
@@ -1,7 +1,6 @@
 // --- receiving ---
 receive WorldModelB.MyScene using ParseScene, ConvertScene ;
 receive indexed WorldModelB.OtherScene ;
-receive WorldModelB.TestingOtherScene ;
 receive Robot.CanReachObjectOfInterestWrapper using ParseReachability, ConvertReachability ;
 receive Robot.OwnedCollaborationZoneNames using ConfigChangeCommandCheckForOwnedCollaborationZone ;
 receive Robot.OccupiedCollaborationZoneNames using CommandCheckForOccupiedCollaborationZone ;
diff --git a/ros3rag.placeB/src/main/java/de/tudresden/inf/st/placeB/SimpleMainB.java b/ros3rag.placeB/src/main/java/de/tudresden/inf/st/placeB/SimpleMainB.java
index 8021b43..a1b38e8 100644
--- a/ros3rag.placeB/src/main/java/de/tudresden/inf/st/placeB/SimpleMainB.java
+++ b/ros3rag.placeB/src/main/java/de/tudresden/inf/st/placeB/SimpleMainB.java
@@ -62,7 +62,7 @@ public class SimpleMainB {
   @SuppressWarnings("unused" )
   Scenario[] allScenarios = new Scenario[] { s2022, sMini, sPlaceworld, sPlaceworldManual };
 
-  final Scenario scenario = sPlaceworld;
+  final Scenario scenario = sMini;
 
   public static void main(String[] args) throws Exception {
     System.out.println("Running SimpleMainB");
@@ -79,6 +79,7 @@ public class SimpleMainB {
     config.mqttHost = scenario.mqttHost;
     String filenameInitialSceneB = "src/main/resources/config-scene-b-" + scenario.suffix + ".json";
     config.filenameRegions = "src/main/resources/regions-b-" + scenario.suffix + ".json";
+    config.forB = new Configuration.ConfigurationForB();
     config.forB.reachability = Arrays.asList(
         "src/main/resources/reachability-b-r1-" + scenario.suffix + ".json",
         "src/main/resources/reachability-b-r2-" + scenario.suffix + ".json"
diff --git a/ros3rag.scaling.a/.gitignore b/ros3rag.scaling.a/.gitignore
index 87b4cdd..fc5fdd2 100644
--- a/ros3rag.scaling.a/.gitignore
+++ b/ros3rag.scaling.a/.gitignore
@@ -3,3 +3,4 @@ src/gen-res/
 src/gen/
 out/
 *.class
+world.svg
diff --git a/ros3rag.scaling.a/src/main/jastadd/ScalingModelA.jadd b/ros3rag.scaling.a/src/main/jastadd/ScalingModelA.jadd
index c616245..9df528c 100644
--- a/ros3rag.scaling.a/src/main/jastadd/ScalingModelA.jadd
+++ b/ros3rag.scaling.a/src/main/jastadd/ScalingModelA.jadd
@@ -1,31 +1,25 @@
 aspect Computation {
-  syn JastAddList<LogicalScene> CompleteWorld.getViewList() {
-    JastAddList<LogicalScene> result = new JastAddList<>();
-    for (int i = 0, length = getNumberOfViews(); i < length; i++) {
-      LogicalScene view = new LogicalScene();
-
-      result.addChild(view);
-    }
-    return result;
-  }
   //--- completeWorld ---
   inh CompleteWorld ASTNode.completeWorld();
   eq CompleteWorld.getChild().completeWorld() = this;
 
-  eq CompleteWorld.getScene().regionList() = completeWorld().getRegionList();
+  syn nta Scene CompleteWorld.emptyScene() = new Scene();
+  eq CompleteWorld.emptyScene().regionList() = new JastAddList<>();
 
   eq Region.locationList() {
-    List<DropOffLocation> result = new ArrayList<>();
-    for (String locationName : locationNamesAsList()) {
-      result.add(completeWorld().getScene().resolveObjectOfInterest(locationName).asDropOffLocation());
-    }
-    return result;
+//    List<DropOffLocation> result = new ArrayList<>();
+//    for (String locationName : locationNamesAsList()) {
+//      result.add(completeWorld().getScene().resolveObjectOfInterest(locationName).asDropOffLocation());
+//    }
+//    return result;
+    // TODO
+    return null;
   }
 }
 
 aspect RagConnectFixes {
-  // FIXME (in ragconnect) when sending list NTAs, the reset method is wrong.
-  private void CompleteWorld.getView_reset() {
-    getViewList_reset();
-  }
+  // // FIXME (in ragconnect) when sending list NTAs, the reset method is wrong.
+  // private void CompleteWorld.getView_reset() {
+  //   getViewList_reset();
+  // }
 }
diff --git a/ros3rag.scaling.a/src/main/jastadd/ScalingModelA.relast b/ros3rag.scaling.a/src/main/jastadd/ScalingModelA.relast
index f2f86f4..f18e4a3 100644
--- a/ros3rag.scaling.a/src/main/jastadd/ScalingModelA.relast
+++ b/ros3rag.scaling.a/src/main/jastadd/ScalingModelA.relast
@@ -1,4 +1,6 @@
 //CompleteWorld ::= <NumberOfViews:int> <DistributionStrategy> /View:WorldModelA*/ ;
 //WorldModelA ::= [Scene] /LogicalScene/ ;
 
-CompleteWorld ::= Region* Scene LogicalScene <NumberOfViews:int> <DistributionStrategy> /View:LogicalScene*/ ;
+CompleteWorld ::= Config View:LogicalScene* ;
+// ObjectAssignment ::= <ObjectName> <RegionName> <LocationName> <SiteIndex:int> ;
+Config ::= <NumberOfViews:int> <NumberOfObjects:int> <NumberOfRobots:int> <Seed:int> <DistributionStrategy> ;
diff --git a/ros3rag.scaling.a/src/main/java/de/tudresden/inf/st/scaling/a/MainScalingA.java b/ros3rag.scaling.a/src/main/java/de/tudresden/inf/st/scaling/a/MainScalingA.java
index 3959d84..fbe6c33 100644
--- a/ros3rag.scaling.a/src/main/java/de/tudresden/inf/st/scaling/a/MainScalingA.java
+++ b/ros3rag.scaling.a/src/main/java/de/tudresden/inf/st/scaling/a/MainScalingA.java
@@ -1,12 +1,96 @@
 package de.tudresden.inf.st.scaling.a;
 
+import de.tudresden.inf.st.jastadd.dumpAst.ast.Dumper;
+import de.tudresden.inf.st.ros3rag.common.ConfigurationScaling;
+import de.tudresden.inf.st.ros3rag.common.Util;
+import de.tudresden.inf.st.scaling.a.ast.*;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+import java.io.IOException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Random;
+
 /**
- * TODO: Add description.
+ * Scaling Case Study - Site A.
  *
  * @author rschoene - Initial contribution
  */
 public class MainScalingA {
-  public static void main(String[] args) {
-    System.out.println("Hi A");
+  private static final Logger logger = LogManager.getLogger(MainScalingA.class);
+  private CompleteWorld world;
+
+  public static void main(String[] args) throws IOException {
+    new MainScalingA().run(args);
+  }
+
+  private void run(@SuppressWarnings("unused") String[] args) throws IOException {
+    logger.info("Hi from A");
+    Path pathToConfig = Paths.get("..",
+        "ros3rag.common", "src", "main", "resources", "config-scaling-mini.yml");
+    ConfigurationScaling config = Util.parseScalingConfig(pathToConfig.toFile());
+
+    world = createWorld(config);
+    generateAndSetViews();
+    Dumper.read(world).dumpAsSVG(Paths.get("world.svg"));
+
+    for (int viewIndex = 0; viewIndex < world.getConfig().getNumberOfViews(); viewIndex++) {
+      world.connectView(
+          Util.mqttUri(config.topicLogicalUpdate, config.mqttHost),
+          viewIndex,
+          true);
+    }
+  }
+
+  private static CompleteWorld createWorld(ConfigurationScaling input) {
+    CompleteWorld result = new CompleteWorld();
+    result.setConfig(new Config()
+        .setNumberOfViews(input.views)
+        .setNumberOfObjects(input.objects)
+        .setNumberOfRobots(input.robots)
+        .setSeed(input.seed)
+    );
+    return result;
+  }
+
+  private void generateAndSetViews() {
+    Random rand = new Random(world.getConfig().getSeed());
+    Map<Integer, Pair<LogicalScene, Map<Integer, LogicalRegion>>> viewAndRegionMap = new HashMap<>();
+    for (int objectIndex = 0; objectIndex < world.getConfig().getNumberOfObjects(); objectIndex++) {
+      LogicalMovableObject obj = new LogicalMovableObject();
+      obj.setName("O" + objectIndex);
+      // randomly pick a target region (essentially the last robot to place it)
+      int targetRegionIndex = rand.nextInt(world.getConfig().getNumberOfRobots());
+      // randomly pick a target view where this information is "stored"
+      int targetViewIndex = rand.nextInt(world.getConfig().getNumberOfViews());
+
+      Pair<LogicalScene, Map<Integer, LogicalRegion>> viewAndRegions = viewAndRegionMap.get(targetViewIndex);
+      if (viewAndRegions == null) {
+        viewAndRegions = new Pair<>(new LogicalScene(), new HashMap<>());
+        viewAndRegionMap.put(targetViewIndex, viewAndRegions);
+      }
+      LogicalScene targetView = viewAndRegions._1;
+      targetView.addLogicalMovableObject(obj);
+
+      LogicalRegion targetRegion = viewAndRegions._2.get(targetRegionIndex);
+      if (targetRegion == null) {
+        targetRegion = new LogicalRegion();
+        targetRegion.setName("Region" + targetRegionIndex);
+        targetView.addLogicalRegion(targetRegion);
+        viewAndRegions._2.put(targetRegionIndex, targetRegion);
+      }
+
+      targetRegion.addContainedObject(obj);
+      obj.setNameOfMyLocation("L_" + targetRegion.getName()); // imaginary name of a location
+    }
+
+    for (int viewIndex = 0; viewIndex < world.getConfig().getNumberOfViews(); viewIndex++) {
+      Pair<LogicalScene, Map<Integer, LogicalRegion>> pair = viewAndRegionMap.get(viewIndex);
+      LogicalScene view = pair != null ? pair._1 : new LogicalScene();
+      world.addView(view);
+    }
   }
 }
diff --git a/ros3rag.scaling.a/src/main/resources/config-scene-a.json b/ros3rag.scaling.a/src/main/resources/config-scene-a.json
index 92b9ce4..53ff245 100644
--- a/ros3rag.scaling.a/src/main/resources/config-scene-a.json
+++ b/ros3rag.scaling.a/src/main/resources/config-scene-a.json
@@ -19,6 +19,5 @@
   { "id": "objectBlue2","type": "BOX","pos": { "x": -0.3,"y": -0.3,"z": 0.8105 },"size": { "length": 0.031,"width": 0.062,"height": 0.121 },"orientation": { "z": 0.382683,"w": 0.92388 },"color": { "b": 1 } },
   { "id": "objectBlue3","type": "BOX","pos": { "x": 0.4,"z": 0.819 },"size": { "length": 0.031,"width": 0.031,"height": 0.138 },"orientation": { "z": 0.382683,"w": 0.92388 },"color": { "b": 1 } },
   { "id": "objectYellow1","type": "BOX","pos": { "x": 0.4,"z": 0.819 },"size": { "length": 0.031,"width": 0.031,"height": 0.138 },"orientation": { "z": 0.382683,"w": 0.92388 },"color": { "r": 1, "g": 1 } },
-  { "id": "objectPurple1","type": "BOX","pos": { "x": 0.3,"z": 0.819 },"size": { "length": 0.031,"width": 0.031,"height": 0.138 },"orientation": { "z": 0.382683,"w": 0.92388 },"color": { "r": 1, "b": 1 } },
-  { "id": "arm","type": "ARM","pos": { "z": 0.75 },"size": { },"orientation": { "w": 1 },"color": { "r": 1.00,"g": 1.00,"b": 1.00 } }
+  { "id": "objectPurple1","type": "BOX","pos": { "x": 0.3,"z": 0.819 },"size": { "length": 0.031,"width": 0.031,"height": 0.138 },"orientation": { "z": 0.382683,"w": 0.92388 },"color": { "r": 1, "b": 1 } }
 ] }
diff --git a/ros3rag.scaling.b/src/main/jastadd/ScalingModelB.jadd b/ros3rag.scaling.b/src/main/jastadd/ScalingModelB.jadd
new file mode 100644
index 0000000..e93e7ce
--- /dev/null
+++ b/ros3rag.scaling.b/src/main/jastadd/ScalingModelB.jadd
@@ -0,0 +1,3 @@
+aspect ScalingB {
+
+}
diff --git a/ros3rag.scaling.b/src/main/java/de/tudresden/inf/st/scaling/b/ConfigurationScalingB.java b/ros3rag.scaling.b/src/main/java/de/tudresden/inf/st/scaling/b/ConfigurationScalingB.java
deleted file mode 100644
index bdbd643..0000000
--- a/ros3rag.scaling.b/src/main/java/de/tudresden/inf/st/scaling/b/ConfigurationScalingB.java
+++ /dev/null
@@ -1,29 +0,0 @@
-package de.tudresden.inf.st.scaling.b;
-
-import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
-
-import java.util.List;
-
-/**
- * New Data class for initial configuration.
- *
- * @author rschoene - Initial contribution
- */
-@JsonIgnoreProperties(ignoreUnknown = true)
-public class ConfigurationScalingB {
-  public String mqttHost;
-  public String filenameInitialScene;
-  public boolean useReachability;
-  public String coordinatorMqttTopicPrefix;
-  public List<ReachabilityConfig> reachability;
-  public int numberOfRobots;
-
-  public static class ReachabilityConfig {
-    public String idRobot;
-    public String filename;
-  }
-
-  public boolean useCoordinator() {
-    return coordinatorMqttTopicPrefix != null;
-  }
-}
diff --git a/ros3rag.scaling.b/src/main/java/de/tudresden/inf/st/scaling/b/MainScalingB.java b/ros3rag.scaling.b/src/main/java/de/tudresden/inf/st/scaling/b/MainScalingB.java
index c9c8f8c..6d33337 100644
--- a/ros3rag.scaling.b/src/main/java/de/tudresden/inf/st/scaling/b/MainScalingB.java
+++ b/ros3rag.scaling.b/src/main/java/de/tudresden/inf/st/scaling/b/MainScalingB.java
@@ -1,12 +1,80 @@
 package de.tudresden.inf.st.scaling.b;
 
+import de.tudresden.inf.st.ros3rag.common.ConfigurationScaling;
+import de.tudresden.inf.st.ros3rag.common.Util;
+import de.tudresden.inf.st.scaling.b.ast.*;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+import java.io.IOException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+
 /**
- * TODO: Add description.
+ * Scaling Case Study - Site B.
  *
  * @author rschoene - Initial contribution
  */
 public class MainScalingB {
-  public static void main(String[] args) {
-    System.out.println("Hi B");
+  private static final Logger logger = LogManager.getLogger(MainScalingB.class);
+  private WorldModelB world;
+
+  public static void main(String[] args) throws IOException {
+    new MainScalingB().run(args);
+  }
+
+  private void run(@SuppressWarnings("unused") String[] args) throws IOException {
+    logger.info("Hi from B");
+    Path pathToConfig = Paths.get("..",
+        "ros3rag.common", "src", "main", "resources", "config-scaling-mini.yml");
+    ConfigurationScaling config = Util.parseScalingConfig(pathToConfig.toFile());
+
+    world = new WorldModelB();
+    generateWorld(config);
+  }
+
+  private void generateWorld(ConfigurationScaling config) throws IOException {
+    // start region
+    world.addRegion(new Region().setName("Start").setLocationNames(locationsFor("Start", config)));
+
+    // robots
+    for (int robotIndex = 0; robotIndex < config.robots; robotIndex++) {
+      // region of the robot
+      String regionOfRobot = "Region" + robotIndex;
+      world.addRegion(new Region().setName(regionOfRobot).setLocationNames(locationsFor(regionOfRobot, config)));
+
+      Robot robot = new Robot().setName("ARM" + robotIndex);
+
+      // reachability
+      CanReachObjectOfInterestWrapper wrapper = new CanReachObjectOfInterestWrapper();
+      // each robot arm can reach the region with the same index as the arm (and the start region, for the first robot)
+      if (robotIndex == 0) {
+        for (String location : world.findRegion("Start").locationNamesAsList()) {
+          wrapper.addCanReachObjectOfInterest(new CanReachObjectOfInterest(location));
+        }
+      }
+      for (String location : world.findRegion(regionOfRobot).locationNamesAsList()) {
+        wrapper.addCanReachObjectOfInterest(new CanReachObjectOfInterest(location));
+      }
+      robot.setCanReachObjectOfInterestWrapper(wrapper);
+      world.addRobot(robot);
+    }
+
+    // other scenes
+    for (int sceneIndex = 0; sceneIndex < config.views; sceneIndex++) {
+      world.addOtherScene(new LogicalScene());
+      world.connectOtherScene(config.topicLogicalUpdate, sceneIndex);
+    }
+
+    // my scene
+    world.setMyScene(new Scene());
+  }
+
+  private String locationsFor(String regionName, ConfigurationScaling config) {
+    return IntStream.range(0, config.objects)
+        .mapToObj(index -> "P-" + regionName + index)
+        .collect(Collectors.joining(","));
   }
 }
-- 
GitLab