Source code for jupedsim.models.collision_free_speed_v3

# SPDX-License-Identifier: LGPL-3.0-or-later

import warnings
from dataclasses import dataclass

try:
    from warnings import deprecated
except ImportError:
    from deprecated import deprecated

import jupedsim.native as py_jps


[docs] @dataclass(kw_only=True) class CollisionFreeSpeedModelV3: """Collision Free Speed Model V3 This variant keeps per-agent interaction parameters and uses bounded rotational steering around the desired direction. """ pass
[docs] @dataclass(kw_only=True) class CollisionFreeSpeedModelV3AgentParameters: """ Agent parameters for Collision Free Speed Model V3. V3 separates direction and speed updates: the walking direction is obtained by rotating a reference direction (the desired direction bent by wall repulsion) toward the side opposite the most relevant forward neighbor, while the walking speed is computed from a scalar spacing using the optimal-velocity relation. The heading angle is relaxed in time to suppress jitter. .. note:: Instances of this type are copied when creating the agent, you can safely create one instance of this type and modify it between calls to ``add_agent``. E.g.: .. code:: python positions = [...] # List of initial agent positions params = CollisionFreeSpeedModelV3AgentParameters(desired_speed=0.9) for p in positions: params.position = p sim.add_agent(params) Attributes: position: Position of the agent. time_gap: Time constant that describes how fast a pedestrian closes gaps. desired_speed: Maximum (free) walking speed of the agent. radius: Radius of the agent. journey_id: Id of the journey the agent follows. stage_id: Id of the stage the agent targets. strength_neighbor_repulsion: Maximum turning angle authority (clamped against ``theta_max_upper_bound``). range_neighbor_repulsion: Base perception range; combined with the scale factors below to form the anisotropic decay lengths ``r_x = range_neighbor_repulsion * range_x_scale`` and ``r_y = range_neighbor_repulsion * range_y_scale``. strength_geometry_repulsion: Strength of wall repulsion that bends the reference direction. range_geometry_repulsion: Decay length of wall repulsion. range_x_scale: Longitudinal aspect factor for the perception field. range_y_scale: Lateral aspect factor for the perception field. theta_max_upper_bound: Hard upper bound on the per-step turning angle. agent_buffer: Buffer distance subtracted from spacing in the optimal-velocity relation; shifts the speed-zero point to a positive spacing. """ position: tuple[float, float] = (0.0, 0.0) time_gap: float = 1.0 desired_speed: float = 1.2 radius: float = 0.2 journey_id: int = 0 stage_id: int = 0 strength_neighbor_repulsion: float = 8.0 range_neighbor_repulsion: float = 0.1 strength_geometry_repulsion: float = 5.0 range_geometry_repulsion: float = 0.02 range_x_scale: float = 20.0 range_y_scale: float = 8.0 theta_max_upper_bound: float = 1.57 agent_buffer: float = 0.0 def __init__( self, *, position: tuple[float, float] = (0.0, 0.0), time_gap: float = 1.0, desired_speed: float = 1.2, v0: float | None = None, radius: float = 0.2, journey_id: int = 0, stage_id: int = 0, strength_neighbor_repulsion: float = 8.0, range_neighbor_repulsion: float = 0.1, strength_geometry_repulsion: float = 5.0, range_geometry_repulsion: float = 0.02, range_x_scale: float = 20.0, range_y_scale: float = 8.0, theta_max_upper_bound: float = 1.57, agent_buffer: float = 0.0, ): self.position = position self.time_gap = time_gap if v0 is not None: warnings.warn( "'v0' is deprecated, use 'desired_speed' instead.", DeprecationWarning, stacklevel=2, ) self.desired_speed = v0 else: self.desired_speed = desired_speed self.radius = radius self.journey_id = journey_id self.stage_id = stage_id self.strength_neighbor_repulsion = strength_neighbor_repulsion self.range_neighbor_repulsion = range_neighbor_repulsion self.strength_geometry_repulsion = strength_geometry_repulsion self.range_geometry_repulsion = range_geometry_repulsion self.range_x_scale = range_x_scale self.range_y_scale = range_y_scale self.theta_max_upper_bound = theta_max_upper_bound self.agent_buffer = agent_buffer @property @deprecated("deprecated, use 'desired_speed' instead.") def v0(self) -> float: return self.desired_speed @v0.setter @deprecated("deprecated, use 'desired_speed' instead.") def v0(self, v0): self.desired_speed = v0 def as_native( self, ) -> py_jps.CollisionFreeSpeedModelV3AgentParameters: return py_jps.CollisionFreeSpeedModelV3AgentParameters( position=self.position, time_gap=self.time_gap, desired_speed=self.desired_speed, radius=self.radius, journey_id=self.journey_id, stage_id=self.stage_id, strength_neighbor_repulsion=self.strength_neighbor_repulsion, range_neighbor_repulsion=self.range_neighbor_repulsion, strength_geometry_repulsion=self.strength_geometry_repulsion, range_geometry_repulsion=self.range_geometry_repulsion, range_x_scale=self.range_x_scale, range_y_scale=self.range_y_scale, theta_max_upper_bound=self.theta_max_upper_bound, agent_buffer=self.agent_buffer, )
[docs] class CollisionFreeSpeedModelV3State: def __init__(self, backing): self._obj = backing @property def time_gap(self) -> float: return self._obj.time_gap @time_gap.setter def time_gap(self, time_gap): self._obj.time_gap = time_gap @property def desired_speed(self) -> float: return self._obj.desired_speed @desired_speed.setter def desired_speed(self, desired_speed): self._obj.desired_speed = desired_speed @property @deprecated("deprecated, use 'desired_speed' instead.") def v0(self) -> float: return self._obj.desired_speed @v0.setter @deprecated("deprecated, use 'desired_speed' instead.") def v0(self, v0): self._obj.desired_speed = v0 @property def radius(self) -> float: return self._obj.radius @radius.setter def radius(self, radius): self._obj.radius = radius @property def strength_neighbor_repulsion(self) -> float: return self._obj.strength_neighbor_repulsion @strength_neighbor_repulsion.setter def strength_neighbor_repulsion(self, strength_neighbor_repulsion): self._obj.strength_neighbor_repulsion = strength_neighbor_repulsion @property def range_neighbor_repulsion(self) -> float: return self._obj.range_neighbor_repulsion @range_neighbor_repulsion.setter def range_neighbor_repulsion(self, range_neighbor_repulsion): self._obj.range_neighbor_repulsion = range_neighbor_repulsion @property def strength_geometry_repulsion(self) -> float: return self._obj.strength_geometry_repulsion @strength_geometry_repulsion.setter def strength_geometry_repulsion(self, strength_geometry_repulsion): self._obj.strength_geometry_repulsion = strength_geometry_repulsion @property def range_geometry_repulsion(self) -> float: return self._obj.range_geometry_repulsion @range_geometry_repulsion.setter def range_geometry_repulsion(self, range_geometry_repulsion): self._obj.range_geometry_repulsion = range_geometry_repulsion @property def range_x_scale(self) -> float: return self._obj.range_x_scale @range_x_scale.setter def range_x_scale(self, range_x_scale): self._obj.range_x_scale = range_x_scale @property def range_y_scale(self) -> float: return self._obj.range_y_scale @range_y_scale.setter def range_y_scale(self, range_y_scale): self._obj.range_y_scale = range_y_scale @property def theta_max_upper_bound(self) -> float: return self._obj.theta_max_upper_bound @theta_max_upper_bound.setter def theta_max_upper_bound(self, theta_max_upper_bound): self._obj.theta_max_upper_bound = theta_max_upper_bound @property def agent_buffer(self) -> float: return self._obj.agent_buffer @agent_buffer.setter def agent_buffer(self, agent_buffer): self._obj.agent_buffer = agent_buffer