Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(perception): simplified configuration for perception index #351

Merged
merged 12 commits into from
Oct 4, 2023
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"messageCacheTime": "30s",
"encodePayloads": true,
"eventSchedulerThreads": 1,
"navigationConfiguration": {
"type": "database"
},
"perceptionConfiguration": {
"vehicleIndex": {
"enabled": true
},
"trafficLightIndex": {
"enabled": true
},
"wallIndex": {
"enabled": false
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -369,8 +369,10 @@ this, new StartApplications(chargingStationUnit.getId(), chargingStationRegistra
* @param trafficLightRegistration traffic light
*/
public void registerTrafficLight(TrafficLightRegistration trafficLightRegistration) {
if (!trafficLightRegistration.getMapping().hasApplication()
&& SimulationKernel.SimulationKernel.getConfiguration().perceptionConfiguration.trafficLightIndex == null) {
// if traffic light index is enabled, we need traffic light state information for all traffic lights via subscriptions
boolean isTrafficLightIndexEnabled = SimulationKernel.SimulationKernel.getConfiguration().perceptionConfiguration.trafficLightIndex != null &&
SimulationKernel.SimulationKernel.getConfiguration().perceptionConfiguration.trafficLightIndex.enabled;
if (!trafficLightRegistration.getMapping().hasApplication() && !isTrafficLightIndexEnabled) {
return;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,12 +85,13 @@ public VehicleUnit(String vehicleName, VehicleType vehicleType, final GeoPoint i
.getCentralNavigationComponent().getRouting()).getScenarioDatabase();
}

if (SimulationKernel.SimulationKernel.getConfiguration().perceptionConfiguration.vehicleIndex != null) {
perceptionModule = SimulationKernel.SimulationKernel.getConfiguration().perceptionConfiguration.vehicleIndex
.createPerceptionModule(this, database, getOsLog());
if (SimulationKernel.SimulationKernel.getCentralPerceptionComponent().getTrafficObjectIndex() != null) {
perceptionModule = SimulationKernel.SimulationKernel.getCentralPerceptionComponent()
.getTrafficObjectIndex().createPerceptionModule(this, database, getOsLog());
} else {
perceptionModule = new NopPerceptionModule(this, database, getOsLog());
}

}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,34 +17,21 @@

import org.eclipse.mosaic.fed.application.ambassador.SimulationKernel;
import org.eclipse.mosaic.fed.application.ambassador.simulation.perception.index.TrafficObjectIndex;
import org.eclipse.mosaic.fed.application.ambassador.simulation.perception.index.objects.TrafficLightObject;
import org.eclipse.mosaic.fed.application.ambassador.simulation.perception.index.objects.VehicleObject;
import org.eclipse.mosaic.fed.application.ambassador.simulation.perception.index.providers.TrafficLightMap;
import org.eclipse.mosaic.fed.application.ambassador.simulation.perception.index.providers.VehicleMap;
import org.eclipse.mosaic.fed.application.config.CApplicationAmbassador;
import org.eclipse.mosaic.fed.application.config.CPerception;
import org.eclipse.mosaic.interactions.traffic.TrafficLightUpdates;
import org.eclipse.mosaic.interactions.traffic.VehicleUpdates;
import org.eclipse.mosaic.lib.database.Database;
import org.eclipse.mosaic.lib.geo.CartesianRectangle;
import org.eclipse.mosaic.lib.math.Vector3d;
import org.eclipse.mosaic.lib.objects.trafficlight.TrafficLightGroup;
import org.eclipse.mosaic.lib.objects.trafficlight.TrafficLightGroupInfo;
import org.eclipse.mosaic.lib.objects.vehicle.VehicleData;
import org.eclipse.mosaic.lib.objects.vehicle.VehicleType;
import org.eclipse.mosaic.lib.routing.Routing;
import org.eclipse.mosaic.lib.spatial.Edge;
import org.eclipse.mosaic.lib.util.PerformanceMonitor;
import org.eclipse.mosaic.rti.api.InternalFederateException;

import com.google.common.collect.Iterables;
import org.apache.commons.lang3.Validate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Collection;
import java.util.List;
import java.util.Map;

/**
* The {@link CentralPerceptionComponent} is responsible for keeping a spatial index of all vehicles,
* which allows fast querying of nearby vehicles.
Expand All @@ -57,7 +44,7 @@ public class CentralPerceptionComponent {
/**
* Configuration containing parameters for setting up the spatial indexes.
*/
private final CApplicationAmbassador.CPerception configuration;
private final CPerception configuration;

/**
* The spatial index used to store and find objects by their positions.
Expand All @@ -84,7 +71,7 @@ public class CentralPerceptionComponent {
*/
private boolean updateTrafficLightIndex = false;

public CentralPerceptionComponent(CApplicationAmbassador.CPerception perceptionConfiguration) {
public CentralPerceptionComponent(CPerception perceptionConfiguration) {
this.configuration = Validate.notNull(perceptionConfiguration, "perceptionConfiguration must not be null");
}

Expand All @@ -99,38 +86,21 @@ public void initialize() throws InternalFederateException {
// evaluate bounding box for perception
scenarioBounds = configuration.perceptionArea == null
? routing.getScenarioBounds() : configuration.perceptionArea.toCartesian();
// see what backends are configured
boolean vehicleIndexConfigured = configuration.vehicleIndex != null;
boolean trafficLightIndexConfigured = configuration.trafficLightIndex != null;

TrafficObjectIndex.Builder indexBuilder = new TrafficObjectIndex.Builder(LOG);
if (scenarioBounds.getArea() <= 0) {
LOG.warn("The bounding area of the scenario could not be determined. Defaulting to low performance spatial index.");
if (vehicleIndexConfigured) { // if configured default to map index
indexBuilder.withVehicleIndex(new VehicleMap());
}
if (trafficLightIndexConfigured) { // if configured default to map index
indexBuilder.withTrafficLightIndex(new TrafficLightMap());
}
} else {
if (vehicleIndexConfigured) {
indexBuilder.withVehicleIndex(configuration.vehicleIndex);
}
if (trafficLightIndexConfigured) {
indexBuilder.withTrafficLightIndex(configuration.trafficLightIndex);
}
if (configuration.vehicleIndex != null) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We lost the validation of the scenarioBounds here, but maybe this isn't really necessary in the first place

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I also didn't see the reason for this check.

indexBuilder.withVehicleIndex(configuration.vehicleIndex.create());
}
if (configuration.trafficLightIndex != null) {
indexBuilder.withTrafficLightIndex(configuration.trafficLightIndex.create());
}
if (routing instanceof Database) {
Database dbRouting = (Database) routing;
if (!dbRouting.getBuildings().isEmpty()) {
indexBuilder.withWallIndex(configuration.wallIndex, (Database) routing);
if (!dbRouting.getBuildings().isEmpty() && configuration.wallIndex != null) {
indexBuilder.withWallIndex(configuration.wallIndex.create(), (Database) routing);
}
}
trafficObjectIndex = indexBuilder.build();

if (configuration.measurePerformance) {
trafficObjectIndex = new MonitoringTrafficObjectIndexProvider(trafficObjectIndex, PerformanceMonitor.getInstance());
}
} catch (Exception e) {
throw new InternalFederateException("Couldn't initialize CentralPerceptionComponent", e);
}
Expand Down Expand Up @@ -212,63 +182,4 @@ public void updateTrafficLights(TrafficLightUpdates trafficLightUpdates) {
updateTrafficLightIndex = true;
}

/**
* Wrapper class to measure atomic calls of update, search and remove of the used spatial index.
*/
static class MonitoringTrafficObjectIndexProvider extends TrafficObjectIndex {
private final PerformanceMonitor monitor;

MonitoringTrafficObjectIndexProvider(TrafficObjectIndex parent, PerformanceMonitor monitor) {
super(parent);
this.monitor = monitor;
}

@Override
public List<VehicleObject> getVehiclesInRange(PerceptionModel searchRange) {
try (PerformanceMonitor.Measurement m = monitor.start("search-vehicle")) {
m.setProperties(getNumberOfVehicles(), SimulationKernel.SimulationKernel.getCurrentSimulationTime()).restart();
return super.getVehiclesInRange(searchRange);
}
}

@Override
public void removeVehicles(Iterable<String> vehiclesToRemove) {
try (PerformanceMonitor.Measurement m = monitor.start("remove-vehicle")) {
m.setProperties(getNumberOfVehicles(), SimulationKernel.SimulationKernel.getCurrentSimulationTime()).restart();
super.removeVehicles(vehiclesToRemove);
}
}

@Override
public void updateVehicles(Iterable<VehicleData> vehiclesToUpdate) {
try (PerformanceMonitor.Measurement m = monitor.start("update-vehicle")) {
m.setProperties(getNumberOfVehicles(), SimulationKernel.SimulationKernel.getCurrentSimulationTime()).restart();
super.updateVehicles(vehiclesToUpdate);
}
}

@Override
public List<TrafficLightObject> getTrafficLightsInRange(PerceptionModel perceptionModel) {
try (PerformanceMonitor.Measurement m = monitor.start("search-traffic-light")) {
m.setProperties(SimulationKernel.SimulationKernel.getCurrentSimulationTime()).restart();
return super.getTrafficLightsInRange(perceptionModel);
}
}

@Override
public void updateTrafficLights(Map<String, TrafficLightGroupInfo> trafficLightsToUpdate) {
try (PerformanceMonitor.Measurement m = monitor.start("update-traffic-light")) {
m.setProperties(SimulationKernel.SimulationKernel.getCurrentSimulationTime()).restart();
super.updateTrafficLights(trafficLightsToUpdate);
}
}

@Override
public Collection<Edge<Vector3d>> getSurroundingWalls(PerceptionModel perceptionModel) {
try (PerformanceMonitor.Measurement m = monitor.start("search-walls")) {
m.setProperties(SimulationKernel.SimulationKernel.getCurrentSimulationTime()).restart();
return super.getSurroundingWalls(perceptionModel);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
/*
* Copyright (c) 2022 Fraunhofer FOKUS and others. All rights reserved.
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*
* Contact: [email protected]
*/

package org.eclipse.mosaic.fed.application.ambassador.simulation.perception.errormodels;

import org.eclipse.mosaic.fed.application.ambassador.simulation.perception.PerceptionModuleOwner;
import org.eclipse.mosaic.fed.application.ambassador.simulation.perception.index.objects.SpatialObject;
import org.eclipse.mosaic.fed.application.ambassador.simulation.perception.index.objects.VehicleObject;
import org.eclipse.mosaic.lib.math.MathUtils;
import org.eclipse.mosaic.lib.math.RandomNumberGenerator;
import org.eclipse.mosaic.lib.math.Vector3d;
import org.eclipse.mosaic.lib.math.VectorUtils;

import java.util.List;

/**
* Adjusts the dimensions of perceived {@link VehicleObject}s. Since the position
* of vehicles is assumed to refer to their front bumper instead of bounding box center,
* their position is adjusted accordingly when the length of the vehicle was changed.
*/
public class DimensionsModifier implements PerceptionModifier {
schwepmo marked this conversation as resolved.
Show resolved Hide resolved

private static final double SIGMA_WIDTH_OFFSET = 0.2; // given in m
private static final double SIGMA_HEIGHT_OFFSET = 0.2; // given in m
private static final double SIGMA_LENGTH_OFFSET = 0.5; // given in m

private final double heightDeviation;
private final double widthDeviation;
private final double lengthDeviation;

private final RandomNumberGenerator rng;


public DimensionsModifier(RandomNumberGenerator rng, double lengthDeviation, double widthDeviation, double heightDeviation) {
this.rng = rng;
this.lengthDeviation = lengthDeviation;
this.widthDeviation = widthDeviation;
this.heightDeviation = heightDeviation;
}

public DimensionsModifier(RandomNumberGenerator rng) {
this.rng = rng;
this.lengthDeviation = SIGMA_LENGTH_OFFSET;
this.widthDeviation = SIGMA_WIDTH_OFFSET;
this.heightDeviation = SIGMA_HEIGHT_OFFSET;
}

@Override
public <T extends SpatialObject> List<T> apply(PerceptionModuleOwner owner, List<T> spatialObjects) {
spatialObjects.stream()
.filter(o -> o instanceof VehicleObject)
.forEach(o -> adjustDimensionsOfVehicle((VehicleObject) o));
return spatialObjects;
}

private void adjustDimensionsOfVehicle(VehicleObject vehicleObject) {

double oldLength = vehicleObject.getLength();

vehicleObject.setDimensions(
Math.abs(rng.nextGaussian(vehicleObject.getLength(), lengthDeviation)),
Math.abs(rng.nextGaussian(vehicleObject.getWidth(), widthDeviation)),
Math.abs(rng.nextGaussian(vehicleObject.getHeight(), heightDeviation))
);

double newLength = vehicleObject.getLength();

if (MathUtils.isFuzzyEqual(newLength, oldLength)) {
return;
}

// move position of vehicle based on length difference since vehicle position is assumed to refer to front bumper and we want to
// squeeze the length around bounding box center
Vector3d direction = VectorUtils.getDirectionVectorFromHeading(vehicleObject.getHeading(), new Vector3d())
.multiply((newLength - oldLength) / 2);
vehicleObject.setPosition(
vehicleObject.getPosition().x + direction.x,
vehicleObject.getPosition().y + direction.y,
vehicleObject.getPosition().z + direction.z
);
}

}

Loading