-
Notifications
You must be signed in to change notification settings - Fork 28
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
GCFM miscalculations when not initialised properly #1438
base: master
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey @chraibi if I understand it correctly the issue only manifests when adding agents, when their orientation vector is erroneously [0,0], right?
If the above is the case, I think it would make more sense to require users to provide a unit length orientation vector as part of the construction? And fail on construction, i.e as early as possible.
Further, the change you made would still allow users to set an initial orientation of [0,0] but would abort(!) the program at runtime. Not what we generally want as this kills the whole process. Instead we should throw an exception and always do the check, this way we can properly inform the user.
Also: could you please add a regression test that exhibits the problem? Let me know if I should lend you a hand in that.
When using GCFM, agent orientation represents sin/cos values for ellipse orientation, but defaults to (0,0) in constructor. This causes issues since (0,0) is an invalid sin/cos pair. If orientation remains (0,0), assume it wasn't set by user and automatically initialize it to point towards agent's target position.
Added conditional checks to set the scaling factor to 1 when model1.v0 or model2.v0 is zero.
in the case of two agents on the line: One moving toward the other, who is not moving, we have the following situation: - The driving force and repulsive force cancel out but don’t completely stop the agent, who's speed is very small but not 0. - So, Agent 1 (very) slowly pushes through Agent 2, which is incorrect. An alternative for choosing such a big value would be to introduce an explicit stopping mechanism e.g: if (netForceMagnitude < 1e-3 && model.speed < 1e-3) { update.velocity = Point(0, 0); } else { update.velocity = (agent.orientation * model.speed) + acc * dT; }
True, but an orientation of (0,0) is also a constraint violation because we say "Orientation is a unit length vector", we could also have used an angle in the API when creating the agent and then convert it into a vector internally. This might be a useful API change for a potential 2.0. What do you think? |
TODO: Check for invalid orientations from user during simulation
@Ozaq I find orientation is more intuitive and easier to use than angle. For now, I check for it during the initialization phase. I think this PR solves already the problem I had before. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also you did forget to actually change the defaults on the python layer, the change in the C-API layer would always be override by the python layer.
agent2 = jps.GeneralizedCentrifugalForceModelAgentParameters( | ||
journey_id=journey_id, | ||
stage_id=wp, | ||
position=(3, 1), | ||
) | ||
|
||
agent_id = sim.add_agent(agent) | ||
sim.add_agent(agent2) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do you want to test here? You add an additional Agent and then no new checks are added, this looks incomplete.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
By placing two pedestrians the test fails.
This reproduces the problem with 0 orientation.
@@ -29,7 +29,7 @@ class GeneralizedCentrifugalForceModel: | |||
max_geometry_interaction_distance: float = 2 | |||
max_neighbor_interpolation_distance: float = 0.1 | |||
max_geometry_interpolation_distance: float = 0.1 | |||
max_neighbor_repulsion_force: float = 9 | |||
max_neighbor_repulsion_force: float = 30 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should not change the defaults of our models. We have a different issue open with a similar request for change, see #1391. I think that we should make it obvious that defaults change and provide them as selectable presets.
This change should be removed.
libsimulator/src/Simulation.cpp
Outdated
Point targetPoint = std::get<0>(_journeys.at(agent.journeyId)->Target(agent)); | ||
if((targetPoint - agent.pos).Norm() < 1e-6) { | ||
LOG_WARNING( | ||
"Agent's position ({}, {}) is the same as the target ({}, {}). Set defaul orientation " | ||
"to (1,0)", | ||
agent.pos.x, | ||
agent.pos.y, | ||
targetPoint.x, | ||
targetPoint.y); | ||
agent.orientation = Point(1.0, 0.0); | ||
} | ||
|
||
if(agent.orientation.isInvalidOrientation()) { | ||
Point direction = (targetPoint - agent.pos).Normalized(); | ||
agent.orientation = direction; | ||
} | ||
agent.orientation = agent.orientation.Normalized(); | ||
_operationalDecisionSystem.ValidateAgent(agent, _neighborhoodSearch, *_geometry); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would this whole block to look like this:
if(isZeroLength(agent.orientation)) {
throw SimulationError("Invalid orientation: {}", agent.orientation);
}
agent.orientation = agent.orientation.Normalized();
Note: I am aware that we do not have a 'isZeroLength' function (yet).
libsimulator/src/Simulation.cpp
Outdated
@@ -8,6 +8,7 @@ | |||
#include "OperationalModel.hpp" | |||
#include "Stage.hpp" | |||
#include "Visitor.hpp" | |||
#include <Logger.hpp> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove
@@ -177,17 +178,33 @@ BaseStage::ID Simulation::AddStage(const StageDescription stageDescription) | |||
|
|||
GenericAgent::ID Simulation::AddAgent(GenericAgent&& agent) | |||
{ | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove
libsimulator/src/Point.cpp
Outdated
@@ -1,12 +1,20 @@ | |||
// Copyright © 2012-2024 Forschungszentrum Jülich GmbH | |||
// SPDX-License-Identifier: LGPL-3.0-or-later | |||
#include "Point.hpp" | |||
|
|||
#include "Macros.hpp" | |||
#include <cassert> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is unused.
libsimulator/src/Ellipse.cpp
Outdated
/** | ||
* @brief Computes the point on the ellipse boundary along the line from the ellipse center to point | ||
* P. | ||
* | ||
* Given a point \( P \) in the local coordinate system of the ellipse, this function finds the | ||
* corresponding point on the ellipse that lies on the same line extending from the center through | ||
* \( P \). | ||
* | ||
* **Behavior:** | ||
* - If \( P \) is very close to the ellipse center, it defaults to returning the point \((a, 0)\) | ||
* on the ellipse. | ||
* - Otherwise, it scales the direction from the center to \( P \) by the ellipse’s semi-major and | ||
* semi-minor axes. | ||
* | ||
* @return Point on the ellipse boundary, transformed into the global coordinate system. | ||
*/ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please follow the established documentation style and use /// to indicate doc-style comments. Please omit the brief because we usually use Doxygen with auto-brief, i.e. First line / first sentence is the brief.
libsimulator/src/Ellipse.cpp
Outdated
/** | ||
* @brief Calculates the effective distance between two ellipses. | ||
* | ||
* This function computes the shortest distance between two ellipses. It does so by: | ||
* | ||
* 1. **Coordinate Transformation:** | ||
* Transforms the center of each ellipse into the local coordinate system of the other | ||
* using their orientation vectors. | ||
* | ||
* 2. **Closest Point Determination:** | ||
* Identifies the closest point on each ellipse to the other ellipse in their respective | ||
* coordinate systems. | ||
* | ||
* 3. **Effective Distance Calculation:** | ||
* Calculates the Euclidean distance between these two closest points on the ellipses. | ||
*/ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please follow the established documentation style and use /// to indicate doc-style comments.
libsimulator/src/Ellipse.cpp
Outdated
/** | ||
* @brief Calculates the semi-minor axis (EB) of an ellipse orthogonal to the direction of velocity. | ||
* | ||
* This method computes the ellipse's semi-axis length perpendicular to the object's movement, | ||
* allowing the ellipse to contract or expand based on the provided scaling factor. | ||
* | ||
* @param scale A scaling factor typically in the range \f$ [0, 1] \f$. | ||
* - \f$ \text{scale} = 0 \f$ → returns \f$ B_{\text{max}} \f$. | ||
* - \f$ \text{scale} = 1 \f$ → returns \f$ B_{\text{min}} \f$. | ||
* @return The computed semi-axis length orthogonal to the velocity direction. | ||
* | ||
* @note Values of `scale` outside the \f$ [0, 1] \f$ range may produce unexpected results. | ||
* @warning No input validation is performed on the `scale` parameter. | ||
*/ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please follow the established documentation style and use /// to indicate doc-style comments.
libsimulator/src/Ellipse.cpp
Outdated
/** | ||
* @brief Calculates the semi-major axis (EA) of an ellipse based on the given speed. | ||
* | ||
* The ellipse adapts dynamically depending on the agent's speed. This method computes | ||
* the semi-axis length in the direction of movement, reflecting how the ellipse | ||
* elongates as speed increases. | ||
* | ||
* @param speed The current speed of the object (must be non-negative). | ||
* @return The computed semi-axis length in the velocity direction. | ||
* | ||
*/ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please follow the established documentation style and use /// to indicate doc-style comments.
I found a bug in the calculation of the ellipse distances.
Since orientation is a unit vector, it directly provides the cosine and sine of the rotation angle.
However, at first the orientation might be a zero vector.
In this PR, I will check all equations related to ellipses and update their documentation.
Hopefully, by then we will have a correctly performing gcfm.