..
  *******************************************************************************
  Copyright (c) 2021 in-tech GmbH
                2022-2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)

  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
  *******************************************************************************

.. _scenario:

Scenario
========

.. _scenario_overview:

Overview
--------

The scenario configuration file (``*.xosc``) describes all dynamic configurations of a simulation run, i.e. position of various road users as well as conditional events that change the behavior of the simulation during the run.
The scenario control is carried out using the `OpenScenarioEngine <https://gitlab.eclipse.org/eclipse/openpass/openscenario1_engine>`_, which processes scenarios according to `ASAM OpenSCENARIO <https://www.asam.net/standards/detail/openscenario/>`_.
It is interfaced using the `MantleAPI <https://gitlab.eclipse.org/eclipse/openpass/mantle-api>`_.
For the list of MantleAPI features supported by |op| see :ref:`scenario_api_support`.

At the time of writing, the OpenScenarioEngine processes scenario configurations in version 1.1.1, but please refer to the corresponding documentations for possible and implemented features.

In the following, the most important features for openPASS are described.

.. _scenario_parameterdeclaration:

ParameterDeclarations
---------------------

The tag ``ParameterDeclarations`` allow to define generic parameters, which can be referenced later the file by its name, prefixed with ``$``.

**Example declaration**

.. code-block:: xml

   <ParameterDeclarations>
     <ParameterDeclaration name="simulation_time" parameterType="double" value="123.4"/>
   </ParameterDeclarations>

**Example usage**

.. code-block:: xml

   <StopTrigger>
     <ConditionGroup>
       <Condition name="EndTime" delay="0" conditionEdge="rising">
         <ByValueCondition>
           <SimulationTimeCondition value="$simulation_time" rule="greaterThan"/>
         </ByValueCondition>
       </Condition>
     </ConditionGroup>
   </StopTrigger>

.. list-table::
   :header-rows: 1

   * - Supported ParameterTypes
   * - string
   * - integer
   * - double

.. note:: Only ``string`` allows empty values.

.. _scenario_catalogs:

Catalogs
--------

The ``Catalogs`` tag defines locations of various other files containing sub features of OpenSCENARIO for easier reusing (and written in the same format).

The following catalogs are the most important:

- :ref:`scenario_vehiclemodels`
- :ref:`scenario_pedestrianmodels`
- TrajectoryCatalog for the case that a *FollowTrajectory action* is defined

The VehicleCatalog is also used by |op| itself for spawning of Common vehicles and therefore mandatory.

**Example**

.. literalinclude:: /../../../repo/sim/contrib/examples/Common/Scenario.xosc
   :language: xml
   :dedent: 2
   :start-at: <CatalogLocations>
   :end-at: </CatalogLocations>

.. _scenario_vehiclemodels:

VehicleCatalog
~~~~~~~~~~~~~~

This path is mandatory.
It has to contain a file named "VehicleModelsCatalog.xosc".
This file contains the available vehicle model catalogs for the simulation.
For each vehicle the physical parameters are stored here.

.. list-table::
   :header-rows: 1

   * - Supported Models
   * - car_bmw_i3
   * - car_bmw_3
   * - car_bmw_7_1
   * - car_bmw_7_2
   * - car_mini_cooper
   * - bus
   * - truck
   * - bicycle


**Example Catalog:**

:download:`/../../../repo/sim/contrib/examples/Common/Vehicles/VehicleModelsCatalog.xosc`

.. _scenario_pedestrianmodels:

PedestrianCatalog
~~~~~~~~~~~~~~~~~

It contains the available pedestrian model catalogs for the simulation.
For each pedestrian the physical parameters are stored here.

.. note::

  Within |op|, pedestrian models are internally handled the same way as vehicle models, i.e. they behave like simplified vehicles.
  *Meaningless* parameters, such as *number of gears*, are set to operational defaults.

.. list-table::
   :header-rows: 1

   * - Supported Models
   * - pedestrian_child
   * - pedestrian_adult

**Full Example:** :download:`/../../../repo/sim/contrib/examples/Common/Vehicles/PedestrianModelsCatalog.xosc`

.. _scenario_roadnetwork:

RoadNetwork
-----------

.. _OpenDRIVE: https://www.asam.net/standards/detail/opendrive/

The ``RoadNetwork`` tag contains the mandatory reference to the `OpenDRIVE`_ :ref:`scenery`.

**Example**

.. literalinclude:: /../../../repo/sim/contrib/examples/Common/Scenario.xosc
   :language: xml
   :dedent: 2
   :start-at: <RoadNetwork>
   :end-at: </RoadNetwork>

Furthermore the controllers of the traffic lights are defined in this section.
Each controller defines the phases of a set of linked traffic lights (e.g. one junction).

**Example**

.. literalinclude:: /../../../repo/sim/contrib/examples/Configurations/TrafficLight/Scenario.xosc
   :language: xml
   :dedent: 4
   :start-at: <TrafficSignals>
   :end-at: </TrafficSignals>

.. list-table::
   :header-rows: 1

   * - Supported States
   * - off
   * - red
   * - yellow
   * - green
   * - red yellow
   * - yellow flashing

.. _scenario_entities:

Entities
--------

The ``Entities`` tag defines all agents that are present at the start of the simulation at predefined positions.
There may be any number of these so called **Scenario Agents** (also zero).

.. note:: EntitySelections are currently not supported by the OpenScenarioEngine

An entity consits of a ``VehicleModel`` (typically a reference an entry from the VehicleCatalog) and a controller.
The controller is **optional** and if no controller is specified, a *default* contoller will be instantiated, which strictly follows OpenSCENARIO actions as requested by the standard.
Unless requested differently through specific actions, it follows the *default* behaviors `KeepVelocity` and `KeepLateralOffset`.
To use the openPASS specific scenario controller a controller with a single parameter named ``AgentProfile`` needs to be specified.

.. admonition:: AgentProfile and ProfilesCatalog

   The ``AgentProfile`` links to a profile in the mandatory ``ProfilesCatalog.xml`` (see :ref:`profilescatalog`).
   This is an extension w.r.t. the OpenSCENARIO standard, as the standard currently does not allow to specifiy a stochastic composition of entities.

**Example**

.. literalinclude:: /../../../repo/sim/contrib/examples/Common/Scenario.xosc
   :language: xml
   :dedent: 2
   :start-at: <Entities>
   :end-at: </Entities>

**Overriding Parameters**

Parameters defined in the VehicleCatalog can be assigned inside the CatalogReference element.
In this case the assigned parameter will overwrite the definition in the VehicleCatalog.
Otherwise the value defined in the VehicleCatalog is used.
The type of the parameter must match that in the VehicleCatalog.

**Example**

.. code-block:: xml

   <CatalogReference catalogName="VehicleCatalog" entryName="car_mini_cooper">
       <ParameterAssignments>
           <ParameterAssignment parameterRef="Length" value="4.0" />
       </ParameterAssignments>
   </CatalogReference>

.. _scenario_storyboard:

Storyboard
----------

The ``Storyboard`` tag contains the initial setup of the scenario and manipulator actions.
These actions control the behavior of the simulation at runtime based on predefined conditions.
In short it is divided into an ``Init`` phase, an actual ``Story``, and a ``StopTrigger``.

For the definition of the storyboard please refert to the `OpenSCENARIO 1.1.1 Model Definition <https://www.asam.net/static_downloads/ASAM_OpenSCENARIO_V1.1.1_Model_Documentation/modelDocumentation/>`_.

In the following sections, clarifications with respect to |op| will be given:

.. _scenario_init:

Init
~~~~

As desribed above, agents need to be defined in the ``Entities`` section.
For proper spawning they need to be parameterized within the ``Init`` phase:

- A `TeleportAction <https://www.asam.net/static_downloads/ASAM_OpenSCENARIO_V1.1.1_Model_Documentation/modelDocumentation/content/TeleportAction.html>`_ specifies the initial position
  If no TeleportAction is defined the agent will not be spawned (the TeleportAction can also happen inside the ``Story``).
- A `SpeedAction  <https://www.asam.net/static_downloads/ASAM_OpenSCENARIO_V1.1.1_Model_Documentation/modelDocumentation/content/SpeedAction.html>`_ specifies the desired velocity.
  [optional] If not defined, a spawned agent will start at standstill.
- A `FollowRouteAction  <https://www.asam.net/static_downloads/ASAM_OpenSCENARIO_V1.1.1_Model_Documentation/modelDocumentation/content/FollowRouteAction.html>`_ forces the agent onto a specific trajectory
  [optional] If not defined, a random route will be assigned.

.. note:: VisiblilityAction is currently not supported by |op|

**Example: TeleportAction + SpeedAction**

.. literalinclude:: /../../../repo/sim/contrib/examples/Common/Scenario.xosc
   :language: xml
   :dedent: 4
   :start-at: <Init>
   :end-at: </Init>


**Example: TeleportAction + FollowRouteAction**

.. literalinclude:: /../../../repo/sim/contrib/examples/Configurations/OSCAction_FollowRouteAction/Scenario.xosc
   :language: xml
   :dedent: 4
   :start-at: <Init>
   :end-at: </Init>

.. _scenario_story:

Story
~~~~~

The tag ``Story`` is optional and defines all conditional interventions during runtime.
Please refer to the `Model Documentation <https://www.asam.net/static_downloads/ASAM_OpenSCENARIO_V1.2.0_Model_Documentation/modelDocumentation/content/Storyboard.html>`_ for a general overview and the `OpenScenarioEngine <https://gitlab.eclipse.org/eclipse/openpass/openscenario1_engine>`_ for supported actions and conditions within a story.

StopTrigger
~~~~~~~~~~~

It is **mandatory** for openPASS to define a StopTrigger that will fire in any case (otherwise, the simulation will never stop).
This does not necessarily have to be a SimulationTimeCondition, but it is recommended to use it, perhaps in conjunction with another trigger.

Current Restrictions
--------------------

Conditions
~~~~~~~~~~~

|Op| support different kind of conditions, belonging either to ``ByValueCondition`` or ``ByEntityCondition``.
While a **by value condition** triggers based on a specified value and is unrelated to any specific agent, a **by entity condition** is bound to an triggering agent, defined by a mandatory section ``TriggeringEntities``.
Entities can be either ego or scenario agents.

.. note:: Reacting on "common" cars is currently not supported.

Actions
~~~~~~~

The following OpenSCENARIO actions are supported:

- :ref:`scenario_followrouteaction`
- :ref:`scenario_lanechange`
- :ref:`scenario_followtrajectory`
- :ref:`scenario_acquireposition`
- :ref:`scenario_teleportaction`
- :ref:`scenario_speedaction`
- :ref:`scenario_trafficsinkaction`

In addition, the following user defined actions are interpreted:

- :ref:`scenario_componentstatechange`
- :ref:`scenario_defaultCustomCommandAction`

.. _scenario_followrouteaction:

FollowRouteAction
+++++++++++++++++

The FollowRouteAction is mainly used as part of the ``Init`` phase of the Storyboard.
It defines Waypoints, which are located by ``road_id`` and further with ``s`` and ``t`` coordinates.
The Agent will try to follow the specified points.

**Example** *Right turn, by specifying three waypoints*

.. literalinclude:: /../../../repo/sim/contrib/examples/Configurations/OSCAction_FollowRouteAction/Scenario.xosc
   :language: xml
   :dedent: 2
   :start-at: <RoutingAction>
   :end-at: </RoutingAction>

.. _scenario_lanechange:

LaneChangeAction
++++++++++++++++

If this action triggers, the actor is forced to perform a trajectory, calculated at the time of triggering.
The target lane be given either absolute or with respect to another entity.
The trajectory can either have a fixed length (in ``s``) or a fixed time.

Currently |op| only supports the type ``sinusoidal``.

**Example** *with absolute target and fixed length*

.. literalinclude:: /../../../repo/sim/contrib/examples/Configurations/OSCAction_SinusoidalLaneChangeLeft_Absolute/Scenario.xosc
   :language: xml
   :dedent: 14
   :start-at: <Action name="LaneChange">
   :end-at: </Action>

**Example** *with relative target and fixed time*

.. literalinclude:: /../../../repo/sim/contrib/examples/Configurations/OSCAction_SinusoidalLaneChangeLeft_Relative/Scenario.xosc
   :language: xml
   :dedent: 14
   :start-at: <Action name="LaneChange">
   :end-at: </Action>

.. _scenario_followtrajectory:

FollowTrajectoryAction
++++++++++++++++++++++

If triggered, the defined trajectory is relayed as signal to listening components.
The trajectory can be defined either directly in the story or as separate TrajectoryCatalog.
For the points (vertices) of the trajectory only world coordinates, given as ``openScenario::WorldPosition``, are supported.
Right now, the mandatory attributes  *z*, *pitch* and *roll* are ignored.

**Example**

.. literalinclude:: /../../../repo/sim/contrib/examples/Configurations/Pedestrian_Trajectory/Scenario.xosc
   :language: xml
   :dedent: 14
   :start-at: <Action name="Trajectory">
   :end-at: </Action>

**Example** *using a TrajectoryCatalog*

.. code-block:: xml

   <Action name="FollowTrajectory">
     <Private>
       <Routing>
         <FollowTrajectoryAction>
           <CatalogReference catalogName="TrajectoryCatalog.xosc" entryName="TrajectoryA">
         </FollowTrajectoryAction>
       </Routing>
      </Private>
   </Action>

.. _scenario_acquireposition:

AcquirePositionAction
+++++++++++++++++++++

If triggered, the defined position is relayed as signal to listening components.

.. warning:: Currently, this is only supported by the component *FMU_Wrapper* for OSMP messages.

.. warning::

   An FMU might contain routing logic not visible to the openPASS simulation core.
   For that reason, an equivalent `RoutingAction` should be set when using `AcquirePosition`.
   Otherwise the simulation output might contain missing data for fields depending on the localization along the route (`PositionRoute`, `TCoordinate`, `AgentInFront`, ...).

**Example** *(WorldPosition)*

.. code-block:: xml

   <Action name="AcquirePosition">
     <PrivateAction>
       <RoutingAction>
         <AcquirePositionAction>
           <Position>
             <WorldPosition x="1.0" y="2.0" z="0.0" h="3.1415" p="0.0" r="0.0" />
           </Position>
         </AcquirePositionAction>
       </RoutingAction>
     </PrivateAction>
   </Action>

**Example** *(RelativeObjectPosition)*

.. code-block:: xml

    <Action name="AcquirePosition">
      <PrivateAction>
        <RoutingAction>
          <AcquirePositionAction>
            <Position>
              <RelativeObjectPosition dx="1.0" dy="1.0" entityRef="S1"/>
            </Position>
          </AcquirePositionAction>
        </RoutingAction>
      </PrivateAction>
    </Action>

.. _scenario_teleportaction:

TeleportAction
++++++++++++++

The TeleportAction instantly changes the position of an entity.

.. _scenario_trafficsinkaction:

TrafficSinkAction
+++++++++++++++++

The TrafficSinkAction is used to remove agents when they reach a certain position.

.. note::

   At spawning time, the TrafficSinkAction is executed the common traffic is initiated, which means vehicles will spawn at the first timestamp in the defined zone, but are immediately removed at the next timestep.

.. _scenario_speedaction:

SpeedAction
+++++++++++

The SpeedAction adjusts the velocity of an entity based on parameters of the SpeedAction.

.. note::

   If the |op| specific controller is used, the SpeedAction might not reflect actual values used by the simulator due to physical boundaries of the simulator.

**Example** *AbsoulteTargetSpeed*

.. code-block:: xml

   <Action name="SpeedAction">
     <PrivateAction>
       <LongitudinalAction>
         <SpeedAction>
           <SpeedActionDynamics dynamicsShape="step" value="0.0" dynamicsDimension="rate"/>
           <SpeedActionTarget>
             <AbsoluteTargetSpeed value="20"/>
           </SpeedActionTarget>
         </SpeedAction>
       </LongitudinalAction>
     </PrivateAction>
   </Action>

**Example** *RelativeTargetSpeed*

.. code-block:: xml

   <Action name="SpeedAction">
     <PrivateAction>
       <LongitudinalAction>
         <SpeedAction>
           <SpeedActionDynamics dynamicsShape="step" value="0.0" dynamicsDimension="rate"/>
           <SpeedActionTarget>
             <RelativeTargetSpeed entityRef="ScenarioAgent" value="10"
                                  speedTargetValueType="delta" continuous="false"/>
           </SpeedActionTarget>
           </SpeedAction>
       </LongitudinalAction>
     </PrivateAction>
   </Action>

.. _scenario_componentstatechange:

SetComponentState (UserDefinedAction)
+++++++++++++++++++++++++++++++++++++

Command Keyword: ``SetComponentState``

Influences the maximum reachable state of an agent component handled by the ComponentController, i.e. it can either activate or deactivate a component.
For more details see the description of the :ref:`agentcomponents_componentcontroller`.

**Example**

.. code-block:: xml

   <Action name="ComponentStateChange">
       <UserDefinedAction>
           <CustomCommandAction>SetComponentState Dynamics_TrajectoryFollower Acting</CustomCommandAction>
       </UserDefinedAction>
   </Action>

.. _scenario_defaultCustomCommandAction:

DefaultCustomCommandAction (UserDefinedAction)
++++++++++++++++++++++++++++++++++++++++++++++

This is **the** default custom command, and is always selected, if **the first WORD** (Keyword) in the command string is **not** registered as a special custom command.
The command is universally accessible across all components via `ScenarioControlInterface::GetCustomCommands()`, empowering users to define personalized actions tailored to their specific needs.
Once defined, the functionality of this command is unique to the user, based on their custom implementation.

.. admonition:: FMU_Wrapper component for OSMP messages only

   The linked string signal is set as custom action of the TrafficCommand. For more information on OSMP FMUs see the :ref:`components_fmuwrapper` documentation.

**Example**

.. code-block:: xml

  <Action name="CustomParameters">
      <UserDefinedAction>
          <CustomCommandAction>Arbitrary String, e.g. { "hello": "world"}</CustomCommandAction>
      </UserDefinedAction>
  </Action>

.. note::

   Here, "Arbitrary" is first checked, if it matches any other available Keyword for used defined actions, such as :ref:`scenario_componentstatechange`.
