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(charging): provide the charging stations within a certain area #446

Open
wants to merge 8 commits into
base: main
Choose a base branch
from

Conversation

kschrab
Copy link
Contributor

@kschrab kschrab commented Dec 12, 2024

Description

  • New method to provide a list of available charging stations within the vicinity of the vehicle (only for Electric Vehicles).

Issue(s) related to this PR

  • Resolves internal issue 950

Affected parts of the online documentation

Changes in the documentation required?

Definition of Done

Prerequisites

  • You have read CONTRIBUTING.md carefully.
  • You have signed the Contributor License Agreement.
  • Your GitHub user id is linked with your Eclipse Account.

Required

  • The title of this merge request follows the scheme type(scope): description (in the style of Conventional Commits)
  • You have assigned a suitable label to this pull request (e.g., enhancement, or bugfix)
  • origin/main has been merged into your Fork.
  • Coding guidelines have been followed (see CONTRIBUTING.md).
  • All checks on GitHub pass.
  • All tests on Jenkins pass.

Requested (can be enforced by maintainers)

  • New functionality is covered by unit tests or integration tests. Code coverage must not decrease.
  • If a bug has been fixed, a new unit test has been written (beforehand) to prove misbehavior
  • There are no new SpotBugs warnings.

Special notes to reviewer

}

@Serial
private static final long serialVersionUID = 1L;
Copy link
Contributor

Choose a reason for hiding this comment

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

Why do we have the serial number here? If it's an interaction-specific thing, why don't we use it in the response as well?

Copy link
Contributor

Choose a reason for hiding this comment

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

Interaction implements Serializable, if we would do distributed simulation in some way or another and serialize/deserialize interactions between remote hosts, this UID would be used to assure that all sides have the same class version loaded. When adding new Interactions giving a serialVersionUID of 1 is good, indicating version 1.

Now what we should consider though is that we update this ID whenever we change Interactions in a meaningful manner.

(see https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/io/Serializable.html)

I hope this suffices as a explanation 😅

Copy link
Contributor Author

Choose a reason for hiding this comment

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

  1. A specific version is needed especially when storing the serialized objects in files or databases and reading them later. Then the version plays a crucial role to determine if a previously stored object is compatible for deserialization or not. Since we don't do such things, we decided long ago that we use 1 always and everywhere where we implement Serializable.

  2. We transfer interactions between PHABMACS and MOSAIC by using this object-serialization, thus we need to implement the Serializable interface for all interactions, and for all objects which are used by interactions. Nevertheless, since we serialize/deserialize the objects just for the transport from/to PHABMACS, we don't need to care about versioning, thus using version 1 again everywhere.

.tiles
/logs/
Copy link
Contributor

Choose a reason for hiding this comment

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

This should not be necessary, please remove

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@iwillitried yes, there is another .gitignore in mosaic-starter which ignores the logs directory. That should suffice and you can remove the /logs/ entry here.

Copy link
Contributor

Choose a reason for hiding this comment

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

This is still not resolved!

}

@Serial
private static final long serialVersionUID = 1L;
Copy link
Contributor

Choose a reason for hiding this comment

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

Interaction implements Serializable, if we would do distributed simulation in some way or another and serialize/deserialize interactions between remote hosts, this UID would be used to assure that all sides have the same class version loaded. When adding new Interactions giving a serialVersionUID of 1 is good, indicating version 1.

Now what we should consider though is that we update this ID whenever we change Interactions in a meaningful manner.

(see https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/io/Serializable.html)

I hope this suffices as a explanation 😅

@kschrab kschrab added the enhancement New feature or request label Jan 21, 2025
@kschrab kschrab marked this pull request as ready for review January 21, 2025 12:58
public class ChargingStationTree extends ChargingStationIndex {
private final int bucketSize;

private KdTree<ChargingStationObject> chargingStationTree;
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't find the code where this Tree is updated... can you help me? The tree should be updated (= take all data from indexedChargingStations and put it into the tree) latest every time before a search is issued?

Copy link
Contributor

Choose a reason for hiding this comment

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

In my understanding, the Tree uses the object references provided by the indexedChargingStations class variable. The tree just points at these objects

Copy link
Contributor

Choose a reason for hiding this comment

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

Ok, maybe the tree uses the references, this would mean that you continue to have a correct behavior even when CS data is updated.
But as I read the code, you start to have a wrong behavior when CS stations are added or removed.

The code how it is written now has following assumptions:

  • All addChargingStation calls are done before the first updateChargingStation call
  • You have at least one updateChargingStation call before the first "find in tree" call.
    Both are things that might work now, but you cannot assume for the future!

I propose the following, which does not blow up the performance:

  • Firstly, write tests, which show that the current code is not working as expected. This way we can prevent regressions in the future.
  • Set the flag recreateTree = true inside add (and theoretically inside remove)
  • On every search call, check if you need to recreate the tree. If recreateTree==true then build the tree new, and reset the flag to false.
  • Make sure in a test, that a call to update is correctly shown in the tree later

Please create new bug-issues in gitlab for the code parts where you copied this behavior from.

Copy link
Contributor

Choose a reason for hiding this comment

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

  • The KD-Tree implementation used here is not designed to have objects added or removed after initialization, which maybe is a different problem.
  • Also as far as I see it, we don't actually need to ever update anything in this tree as for all intents and purposes we are just interested in the position and id of the charging stations, which is already contained within the registration.
  • In the traffic light tree we used the updateTrafficLights as a hook to initialize the tree (which is hacky in the first place), as we can be sure the all traffic light registrations have been received before the first update. I'm not sure this can be applied for the charging stations as well. However, I'm not certain how we can know if all charging station registrations have been received. 🤷
  • If we actually see the requirement to recreate the tree, we should use a different data structure as recreation scales really poorly.

}

@Override
public void onChargingStationUpdate() {
Copy link
Contributor

Choose a reason for hiding this comment

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

I know that for e.g. TrafficLightTree this does not exist, but please add tests for the functions in ChargingStationIndex and ChargingStationTree

Copy link
Contributor

Choose a reason for hiding this comment

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

please check if the test ApplicationAmbassadorTest.processInteraction_ChargingStationRegistration() is enough or if we need an explicit test for updating the data of the object

Copy link
Contributor

Choose a reason for hiding this comment

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

How I read the processInteraction_ChargingStationRegistration it just shows that the interaction is processed without error, but you don't even have a check which looks if this add is executed correctly, and if you can then find/search/update the CS later.

So no, unfortunately you have to add more specific and detailed testing.

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes we should have a separate Test for the ChargingStationTree.
The SimplePerceptionModule Test contains some implicit testing of the indexes, however I agree we should also have separate tests for all perception indexes.

- Merged contents of ChargingStationTree into ChargingStationIndex
- ChargingStationIndex is not abstract anymore
- small changes regarding function naming and removal of empty lines
Copy link
Contributor Author

@kschrab kschrab left a comment

Choose a reason for hiding this comment

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

Minor changes required. Also, please check if all unit tests are green, currently, ApplicationAmbassadorTest.processInteraction_ChargingStationRegistration fails

.setChargingStationData(chargingStationData);
}

public List<ChargingStationObject>getChargingStationsInCircle(GeoCircle circle) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Code style: missing space before method name

Copy link
Contributor

Choose a reason for hiding this comment

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

done

Comment on lines 75 to 81
public void onChargingStationUpdate() {
if (chargingStationTree == null) { // initialize before first update is called
List<ChargingStationObject> allChargingStations = new ArrayList<>(indexedChargingStations.values());
chargingStationTree = new KdTree<>(new SpatialObjectAdapter<>(), allChargingStations, bucketSize);
treeTraverser = new SpatialTreeTraverser.InRadius<>();
}
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Does this need to be public? I would make that private, rename it to initSearchTree() and move it right below updateChargingStation method where it is needed

Copy link
Contributor

Choose a reason for hiding this comment

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

done

Comment on lines 51 to 53
public void initialize() {
// initialization at first update
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Why do we have this method if we don't do anything here?

Copy link
Contributor

Choose a reason for hiding this comment

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

removed it

public List<ChargingStationData> getChargingStationsInArea(GeoCircle searchArea) {
return SimulationKernel.SimulationKernel.getChargingStationIndex().getChargingStationsInCircle(searchArea)
.stream().map(ChargingStationObject::getChargingStationData)
.collect(Collectors.toList());
Copy link
Contributor Author

Choose a reason for hiding this comment

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

use toList() instead of .collect(Collectors.toList());

Copy link
Contributor

Choose a reason for hiding this comment

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

ok

}

return this.chargingStationIndex;
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

code style: missing blank line after this method.

Copy link
Contributor

Choose a reason for hiding this comment

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

ok

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

public class ChargingStationIndex {
Copy link
Contributor

Choose a reason for hiding this comment

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

After merging Index and Tree, I think we should stick with naming "Tree". If I merge the two files from "Car extends Vehicle" then also what remains is rather a "Car" than a "Vehicle".

public class ChargingStationTree extends ChargingStationIndex {
private final int bucketSize;

private KdTree<ChargingStationObject> chargingStationTree;
Copy link
Contributor

Choose a reason for hiding this comment

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

Ok, maybe the tree uses the references, this would mean that you continue to have a correct behavior even when CS data is updated.
But as I read the code, you start to have a wrong behavior when CS stations are added or removed.

The code how it is written now has following assumptions:

  • All addChargingStation calls are done before the first updateChargingStation call
  • You have at least one updateChargingStation call before the first "find in tree" call.
    Both are things that might work now, but you cannot assume for the future!

I propose the following, which does not blow up the performance:

  • Firstly, write tests, which show that the current code is not working as expected. This way we can prevent regressions in the future.
  • Set the flag recreateTree = true inside add (and theoretically inside remove)
  • On every search call, check if you need to recreate the tree. If recreateTree==true then build the tree new, and reset the flag to false.
  • Make sure in a test, that a call to update is correctly shown in the tree later

Please create new bug-issues in gitlab for the code parts where you copied this behavior from.

}

@Override
public void onChargingStationUpdate() {
Copy link
Contributor

Choose a reason for hiding this comment

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

How I read the processInteraction_ChargingStationRegistration it just shows that the interaction is processed without error, but you don't even have a check which looks if this add is executed correctly, and if you can then find/search/update the CS later.

So no, unfortunately you have to add more specific and detailed testing.

.tiles
/logs/
Copy link
Contributor

Choose a reason for hiding this comment

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

This is still not resolved!

@@ -368,6 +376,9 @@ private void process(final ServerRegistration serverRegistration) {

private void process(final ChargingStationRegistration chargingStationRegistration) {
UnitSimulator.UnitSimulator.registerChargingStation(chargingStationRegistration);
String id = chargingStationRegistration.getMapping().getName();
GeoPoint position = chargingStationRegistration.getMapping().getPosition();
SimulationKernel.SimulationKernel.chargingStationIndex.addChargingStation(id, position);
Copy link
Contributor

Choose a reason for hiding this comment

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

Use SimulationKernel.SimulationKernel.getChargingStationIndex() here

@@ -449,6 +460,8 @@ private void process(final ChargingStationUpdate chargingStationUpdate) {
final AbstractSimulationUnit simulationUnit =
UnitSimulator.UnitSimulator.getUnitFromId(chargingStationData.getName());

SimulationKernel.SimulationKernel.chargingStationIndex.updateChargingStation(chargingStationUpdate.getUpdatedChargingStation());
Copy link
Contributor

Choose a reason for hiding this comment

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

Use SimulationKernel.SimulationKernel.getChargingStationIndex() here.
Also why don't you just use the chargingStationData as input declared in line 459?

@@ -458,6 +471,7 @@ private void process(final ChargingStationUpdate chargingStationUpdate) {
chargingStationData,
EventNicenessPriorityRegister.UPDATE_CHARGING_STATION
);

Copy link
Contributor

Choose a reason for hiding this comment

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

Why did you add this blank line? This makes this method look different from all other in this file

@@ -158,6 +160,12 @@ public ApplicationAmbassador(AmbassadorParameter ambassadorParameter) {
SimulationKernel.SimulationKernel.setCentralPerceptionComponent(centralPerceptionComponent);
}

if (SimulationKernel.SimulationKernel.chargingStationIndex == null) {
// use same bucketsize as TrafficLightTree (see: CPercetion.java) (bucketsize := number of direct children per tree node)
ChargingStationIndex chargingStationIndex = new ChargingStationIndex(20);
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe define the 20 as a constant in the ChargingStationIndex, the way it defined right now is a magic number.

@@ -103,4 +109,10 @@ public void sendChargingStopRequest() {
);
sendInteractionToRti(vehicleChargingStopRequest);
}

public List<ChargingStationData> getChargingStationsInArea(GeoCircle searchArea) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Shouldn't this return ChargingStationObjects?

/**
* The data object that stores all static and dynamic information of the charging station.
*/
private ChargingStationData chargingStationData;
Copy link
Contributor

Choose a reason for hiding this comment

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

This field stores references to the objects contained within the ChargingStationUpdates, which is potentially dangerous. I believe we should copy the relevant information from the ChargingStationData and store it in these objects

Copy link
Contributor

Choose a reason for hiding this comment

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

Looking into the ChargingStationData, I feel like we don't require it at all as we currently are just interested in the position of the charging stations. As far as I see we don't need any info on the charging spots?!

*/
public void updateChargingStation(ChargingStationData chargingStationData) {
initSearchTree();
indexedChargingStations.get(chargingStationData.getName())
Copy link
Contributor

Choose a reason for hiding this comment

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

is there actually anything we want to update about charging stations?

*
* @param searchArea The area where the charging stations are searched
*/
List<ChargingStationData> getChargingStationsInArea(GeoCircle searchArea);
Copy link
Contributor

Choose a reason for hiding this comment

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

Why isn't this returning ChargingStationObjects?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants