From e40ca0f73dd6fc7179c928e8c30e718ec0304eb0 Mon Sep 17 00:00:00 2001 From: Karl Schrab Date: Tue, 25 Jul 2023 18:37:28 +0200 Subject: [PATCH] feat(mapping): configure type distributions for ScenarioVehicle allows defining multiple application types for equal vehicle type names in large sumo scenario Signed-off-by: Karl Schrab --- .../mapping/ambassador/MappingAmbassador.java | 79 +++++++----- .../mapping/ambassador/SpawningFramework.java | 25 +++- .../mosaic/fed/mapping/config/CPrototype.java | 8 +- .../ambassador/MappingAmbassadorTest.java | 21 ++++ .../src/test/resources/mapping_config.json | 112 ++++++++++-------- 5 files changed, 161 insertions(+), 84 deletions(-) diff --git a/fed/mosaic-mapping/src/main/java/org/eclipse/mosaic/fed/mapping/ambassador/MappingAmbassador.java b/fed/mosaic-mapping/src/main/java/org/eclipse/mosaic/fed/mapping/ambassador/MappingAmbassador.java index 2496509ed..6f8022532 100644 --- a/fed/mosaic-mapping/src/main/java/org/eclipse/mosaic/fed/mapping/ambassador/MappingAmbassador.java +++ b/fed/mosaic-mapping/src/main/java/org/eclipse/mosaic/fed/mapping/ambassador/MappingAmbassador.java @@ -15,6 +15,7 @@ package org.eclipse.mosaic.fed.mapping.ambassador; +import org.eclipse.mosaic.fed.mapping.ambassador.weighting.StochasticSelector; import org.eclipse.mosaic.fed.mapping.config.CMappingAmbassador; import org.eclipse.mosaic.fed.mapping.config.CPrototype; import org.eclipse.mosaic.interactions.mapping.VehicleRegistration; @@ -32,6 +33,7 @@ import org.apache.commons.lang3.ObjectUtils; +import java.util.List; import javax.annotation.Nonnull; /** @@ -121,46 +123,59 @@ private void handleInteraction(ScenarioTrafficLightRegistration interaction) { */ private void handleInteraction(ScenarioVehicleRegistration scenarioVehicle) throws InternalFederateException { if (framework != null) { - final CPrototype prototype = framework.getPrototypeByName(scenarioVehicle.getVehicleType().getName()); - if (prototype == null) { - log.debug( - "There is no such prototype \"{}\" configured. No application will be mapped for vehicle \"{}\".", - scenarioVehicle.getVehicleType().getName(), - scenarioVehicle.getId() - ); - return; - } - if (randomNumberGenerator.nextDouble() >= ObjectUtils.defaultIfNull(prototype.weight, 1.0)) { - log.debug( - "This scenario vehicle \"{}\" of prototype \"{}\" will not be equipped due to a weight condition of {}.", - scenarioVehicle.getId(), - scenarioVehicle.getVehicleType().getName(), - prototype.weight - ); - return; + final List typeDistribution = framework.getTypeDistributionByName(scenarioVehicle.getVehicleType().getName()); + if (!typeDistribution.isEmpty()) { + final CPrototype selected = new StochasticSelector<>(typeDistribution, randomNumberGenerator).nextItem(); + sendVehicleRegistrationForScenarioVehicle(scenarioVehicle, selected.group, selected.applications); + } else { + final CPrototype prototype = framework.getPrototypeByName(scenarioVehicle.getVehicleType().getName()); + if (prototype == null) { + log.debug( + "There is no such prototype \"{}\" configured. No application will be mapped for vehicle \"{}\".", + scenarioVehicle.getVehicleType().getName(), + scenarioVehicle.getId() + ); + return; + } + + if (randomNumberGenerator.nextDouble() >= ObjectUtils.defaultIfNull(prototype.weight, 1.0)) { + log.debug( + "This scenario vehicle \"{}\" of prototype \"{}\" will not be equipped due to a weight condition of {}.", + scenarioVehicle.getId(), + scenarioVehicle.getVehicleType().getName(), + prototype.weight + ); + return; + } + sendVehicleRegistrationForScenarioVehicle(scenarioVehicle, prototype.group, prototype.applications); } - final VehicleRegistration vehicleRegistration = new VehicleRegistration( - scenarioVehicle.getTime(), - scenarioVehicle.getName(), - prototype.group, - prototype.applications, - null, - scenarioVehicle.getVehicleType() - ); - try { - log.info("Mapping Scenario Vehicle. time={}, name={}, type={}, apps={}", - framework.getTime(), scenarioVehicle.getName(), scenarioVehicle.getVehicleType().getName(), prototype.applications); - rti.triggerInteraction(vehicleRegistration); - } catch (Exception e) { - throw new InternalFederateException(e); - } } else { log.warn("No mapping configuration available. Skipping {}", scenarioVehicle.getClass().getSimpleName()); } } + private void sendVehicleRegistrationForScenarioVehicle( + ScenarioVehicleRegistration scenarioVehicle, String group, List applications + ) throws InternalFederateException { + final VehicleRegistration vehicleRegistration = new VehicleRegistration( + scenarioVehicle.getTime(), + scenarioVehicle.getName(), + group, + applications, + null, + scenarioVehicle.getVehicleType() + ); + try { + log.info("Mapping Scenario Vehicle. time={}, name={}, type={}, apps={}", + framework.getTime(), scenarioVehicle.getName(), scenarioVehicle.getVehicleType().getName(), applications); + rti.triggerInteraction(vehicleRegistration); + } catch (Exception e) { + throw new InternalFederateException(e); + } + } + @Override protected void processTimeAdvanceGrant(long time) throws InternalFederateException { try { diff --git a/fed/mosaic-mapping/src/main/java/org/eclipse/mosaic/fed/mapping/ambassador/SpawningFramework.java b/fed/mosaic-mapping/src/main/java/org/eclipse/mosaic/fed/mapping/ambassador/SpawningFramework.java index 1976e7be6..eff4da93e 100644 --- a/fed/mosaic-mapping/src/main/java/org/eclipse/mosaic/fed/mapping/ambassador/SpawningFramework.java +++ b/fed/mosaic-mapping/src/main/java/org/eclipse/mosaic/fed/mapping/ambassador/SpawningFramework.java @@ -46,6 +46,7 @@ import org.eclipse.mosaic.rti.api.InternalFederateException; import org.eclipse.mosaic.rti.api.RtiAmbassador; +import com.google.common.collect.Lists; import org.apache.commons.lang3.ObjectUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -65,6 +66,7 @@ public class SpawningFramework { private static final Logger LOG = LoggerFactory.getLogger(SpawningFramework.class); private final List prototypeConfigurations = new ArrayList<>(); + private final Map> typeDistributions = new HashMap<>(); private final Map tls = new HashMap<>(); private final List vehicleFlowGenerators = new ArrayList<>(); private final List rsus = new ArrayList<>(); @@ -172,12 +174,16 @@ public SpawningFramework(CMappingAmbassador mappingConfiguration, } } } + + if (mappingConfiguration.typeDistributions != null) { + SpawningFramework.this.typeDistributions.putAll(mappingConfiguration.typeDistributions); + } + // randomize weights in type-distributions - if (mappingConfiguration.typeDistributions != null - && mappingConfiguration.config != null + if (mappingConfiguration.config != null && mappingConfiguration.config.randomizeWeights ) { - for (List prototypes : mappingConfiguration.typeDistributions.values()) { + for (List prototypes : typeDistributions.values()) { randomizeWeights(rng, prototypes); } } @@ -426,6 +432,19 @@ CPrototype getPrototypeByName(String name) { return null; } + public List getTypeDistributionByName(String name) { + if (name == null) { + return Lists.newArrayList(); + } + + final List types = typeDistributions.get(name); + if (types != null) { + return types; + } + + return Lists.newArrayList(); + } + /** * This method handles a time advance called by the {@link MappingAmbassador}. * diff --git a/fed/mosaic-mapping/src/main/java/org/eclipse/mosaic/fed/mapping/config/CPrototype.java b/fed/mosaic-mapping/src/main/java/org/eclipse/mosaic/fed/mapping/config/CPrototype.java index cd61255cb..6d14da584 100644 --- a/fed/mosaic-mapping/src/main/java/org/eclipse/mosaic/fed/mapping/config/CPrototype.java +++ b/fed/mosaic-mapping/src/main/java/org/eclipse/mosaic/fed/mapping/config/CPrototype.java @@ -15,6 +15,7 @@ package org.eclipse.mosaic.fed.mapping.config; +import org.eclipse.mosaic.fed.mapping.ambassador.weighting.Weighted; import org.eclipse.mosaic.lib.enums.LaneChangeMode; import org.eclipse.mosaic.lib.enums.SpeedMode; import org.eclipse.mosaic.lib.enums.VehicleClass; @@ -31,7 +32,7 @@ *

* If these values are not defined some default values might be applied depending on prototype type. */ -public class CPrototype { +public class CPrototype implements Weighted { /** * The name of this prototype. This identifier is used to match it against @@ -147,6 +148,10 @@ public class CPrototype { */ public CParameterDeviations deviations; + @Override + public double getWeight() { + return weight; + } /** * Creates a copy of this prototype. @@ -202,5 +207,4 @@ public String toString() { + ", applications: " + (applications != null ? applications : "null") + "]"; } - } diff --git a/fed/mosaic-mapping/src/test/java/org/eclipse/mosaic/fed/mapping/ambassador/MappingAmbassadorTest.java b/fed/mosaic-mapping/src/test/java/org/eclipse/mosaic/fed/mapping/ambassador/MappingAmbassadorTest.java index f9621585a..2e4061de1 100644 --- a/fed/mosaic-mapping/src/test/java/org/eclipse/mosaic/fed/mapping/ambassador/MappingAmbassadorTest.java +++ b/fed/mosaic-mapping/src/test/java/org/eclipse/mosaic/fed/mapping/ambassador/MappingAmbassadorTest.java @@ -300,6 +300,27 @@ public void initializeWithMappingFile_scenarioVehicleRegistration() throws Excep Assert.assertNull(lastReceivedInteraction); } + @Test + public void initializeWithMappingFile_scenarioVehicleRegistrationWithTypeDistribution() throws Exception { + final MappingAmbassador ambassador = createMappingAmbassadorWithMappingFile("mapping_config.json"); + ambassador.initialize(0, 100 * TIME.SECOND); + + ambassador.processInteraction(new ScenarioVehicleRegistration(0, "veh_0", new VehicleType("myCarDistribution"))); + assertVehicleRegistration( + "package.appA" + ); + + ambassador.processInteraction(new ScenarioVehicleRegistration(0, "veh_0", new VehicleType("myCarDistribution"))); + assertVehicleRegistration( + "package.appA" + ); + + ambassador.processInteraction(new ScenarioVehicleRegistration(0, "veh_0", new VehicleType("myCarDistribution"))); + assertVehicleRegistration( + "package.appB" + ); + } + @Before public void setup() throws Throwable { when(rtiMock.createRandomNumberGenerator()).thenReturn(new DefaultRandomNumberGenerator(989123)); diff --git a/fed/mosaic-mapping/src/test/resources/mapping_config.json b/fed/mosaic-mapping/src/test/resources/mapping_config.json index 028f2a219..b1866dc44 100644 --- a/fed/mosaic-mapping/src/test/resources/mapping_config.json +++ b/fed/mosaic-mapping/src/test/resources/mapping_config.json @@ -1,49 +1,67 @@ { - "prototypes":[ - { - "name":"PKW", - "accel":2.6, - "decel":4.5, - "length":5.00, - "maxSpeed":70.0, - "minGap":2.5, - "sigma":0.5, - "tau":1 - }, - { - "name":"electricPKW", - "vehicleClass": "ElectricVehicle", - "applications":["org.eclipse.mosaic.app.examples.eventprocessing.sampling.HelloWorldApp", "org.eclipse.mosaic.app.examples.eventprocessing.sampling.IntervalSamplingApp"], - "accel":2.6, - "decel":4.5, - "length":5.00, - "maxSpeed":40.0, - "minGap":2.5, - "sigma":0.5, - "tau":1 - } - ], - "vehicles":[ - { - "startingTime": 5.0, - "targetFlow":1200, - "maxNumberVehicles": 120, - "route":"1", - "types":[ - { - "applications":["org.eclipse.mosaic.app.tutorials.barnim.WeatherWarningApp"], - "name":"PKW", - "weight":0.2 - }, - { - "name":"PKW", - "weight":0.7 - }, - { - "name":"electricPKW", - "weight":0.1 - } - ] - } - ] + "prototypes": [ + { + "name": "PKW", + "accel": 2.6, + "decel": 4.5, + "length": 5.00, + "maxSpeed": 70.0, + "minGap": 2.5, + "sigma": 0.5, + "tau": 1 + }, + { + "name": "electricPKW", + "vehicleClass": "ElectricVehicle", + "applications": [ + "org.eclipse.mosaic.app.examples.eventprocessing.sampling.HelloWorldApp", + "org.eclipse.mosaic.app.examples.eventprocessing.sampling.IntervalSamplingApp" + ], + "accel": 2.6, + "decel": 4.5, + "length": 5.00, + "maxSpeed": 40.0, + "minGap": 2.5, + "sigma": 0.5, + "tau": 1 + } + ], + "vehicles": [ + { + "startingTime": 5.0, + "targetFlow": 1200, + "maxNumberVehicles": 120, + "route": "1", + "types": [ + { + "applications": [ "org.eclipse.mosaic.app.tutorials.barnim.WeatherWarningApp" ], + "name": "PKW", + "weight": 0.2 + }, + { + "name": "PKW", + "weight": 0.7 + }, + { + "name": "electricPKW", + "weight": 0.1 + } + ] + } + ], + "typeDistributions": { + "myCarDistribution": [ + { + "name": "Car", + "group": "CarWithAppA", + "applications": [ "package.appA" ], + "weight": 60 + }, { + "name": "Car", + "group": "CarWithAppB", + "applications": [ "package.appB" ], + "weight": 40 + } + ] + } }