Skip to content

User hooks for Foretify flow control

The following methods are available as hooks that allow you to perform different actions on different flows.

init()

Purpose

Perform various actions when an object is created

Category

Method of any object

Syntax

extend <object>:
    def init() is also:
        <procedural-code>

Syntax parameters

<object>
(Required) Is a struct, actor or scenario.
<procedural-code>
(Required) Is any valid procedural code. See Native methods for more information.

Description

Each object (struct, actor or scenario) has a predefined init() method. init() is called each time a new object is allocated, both when creating new objects in procedural code and when generation allocates new objects. Regarding init() in generation, init() is called before post_plan(). The order is as follows: init() is called, then generation sets all generatable fields for the specific object, then post_plan() is called.

You can extend this method using is_also to initialize non-generatable fields to a computed value, for example. Overwriting this method is not allowed.

Example

In the following example, the call to logger.log_info() prints the value of my_vars.my_speed, which has been initialized to 100kph.

OSC2 code: init() method with is_also
import "$FTX_BASIC/exe_platforms/sumo_ssp/config/sumo_config.osc"

extend test_config:
    set map = "$FTX_PACKAGES/maps/M77_FTX_highway_straight_long_road.xodr"

struct my_vars:
    var my_speed: speed

    def init() is also: my_speed = 100kph

extend top.main:
    my_vars: my_vars

    do serial:
        call logger.log_info("my_speed is $(my_vars.my_speed)")
        sut.car.drive() with: speed([30..60]kph)
    with:
        duration([3..7]s)

on_created()

Purpose

Provides the values for an actor received from the simulator

Category

Method of any agent

Syntax

extend any_agent:
   def on_created(sim_id: string, desc: av_actor_description) is empty 

Syntax Parameters

<sim_id>: <string>
(Required) Specifies the unique ID created by the simulator for the new actor.
<desc>: <av_actor_description>
(Required) Specifies the values for the new actor receieved from the simulator. See definition below.

The struct av_actor_description is defined as:

struct av_actor_description:
    var actor_type: string
    var additional_properties: list of property
    var length: length
    var width: length
    var height: length
<actor_type>: <string>
Actor type.
<additional_properties>: <list of property>
List of optional additional properties.
<length>: <length>
Actor's length.
<width>: <length>
Actor's width.
<height>: <length>
Actor's height.

Description

on_created() is a callback function that is called after an actor is created in the simulator. on_created() provides the actual values for the actor received from the simulator.

on_execution_start()

Purpose

Is called for each actor on simulation start, prior to the simulation's first step

Category

Method of any agent

Syntax

extend any_agent:
    def on_execution_start() is empty

Description

on_execution_start() is called during test execution before the first simulation step.

on_post_plan()

Purpose

Perform various actions after planning is finished and before execution starts

Category

Method of any agent

Syntax

extend any_agent:
    def on_post_plan() is empty

Description

on_post_plan() is called after scenario generation is finished, and it lets you either:

  • Perform some checks and cause a generation retry.
  • Run some code for preparing data based on generated values. This should be done with care, since there may be a generation retry after a call to on_post_plan().

post_plan()

Purpose

Perform various actions after an object is generated

Category

Method of any object

Syntax

extend <object>:
    def post_plan() is also:
        <procedural-code>

Syntax parameters

<object>
(Required) Is a struct, actor or scenario.
<procedural-code>
(Required) Is any valid procedural code. See Native methods for more information.

Description

Each object (struct, actor or scenario) has a predefined post_plan() method. This method is called by Foretify for each object once the generation of the object is completed, after:

  • All generative primitive fields of the object have a value.
  • The post-plan() method of all struct fields of the object has been called.

You can extend this method using is_also to initialize non-generatable fields to a computed value, for example.

Example

In the following example, the initial value for the variable z is calculated on the generated values of x and y.

OSC2 code: post_plan() method
struct foo:
   x, y: int
   var z: int
   def post_plan() is also:
      z = x + y

post_sim_update()

Purpose

Called for each actor after calling update_state()

Category

Method of any agent

Syntax

extend any_agent:
    def post_sim_update() is empty

Description

See Update methods.

pre_sim_update()

Purpose

Called for each actor before calling update_state()

Category

Method of any agent

Syntax

extend any_agent:
    def pre_sim_update() is empty

Description

See Update methods.

update_state()

Purpose

Called when new data for an actor is received from the simulator

Category

Method of any agent

Syntax

extend any_agent:
    def update_state(sim_state: av_actor_state) is empty

Syntax Parameters

<sim_state>: <av_actor_state>
(Required) Specifies the state received from the simulator. See definition below.

The struct sim_state is defined as follows:

struct av_actor_state:
    var position: global_position
    var speed: global_speed
    var angular_speed: global_angular_speed
    var acceleration: global_acceleration
    var collision_info: collision_info
    var controls: actor_controls
    var additional_properties: list of property
<position>: <global_position>
Position of the actor in global coordinates.
<speed>: <global_speed>
Speed of the actor in global coordinates.
<angular_speed>: <global_angular_speed>
Angular speed of the actor in global coordinates.
<acceleration>: <global_acceleration>
Acceleration of the actor in global coordinates.
<collision_info>: <collision_info>
Collision information (includes a single field: var other_actor: physical_object).
<controls>: <actor_controls>
Actor controls. See definition below.
<additional_properties>: <list of property>
Optional additional information.

The struct actor_controls is defined as follows:

struct actor_controls:
    var gear: string
    var hand_brake: bool
    var hazard_lights: bool
    var indicators: av_indicator_state
    # Holds the brake pedal position in percent [0,1]
    var brake_pedal_pos: float
    # Holds the throttle pedal position in percent [0,1]
    var throttle_pedal_pos: float
    # Holds the steering wheel angle
    var steering_wheel_angle: angle
    var siren: bool
    var emergency_lights: bool
<gear>: <string>
Actor's gear.
<hand_brake>: <bool>
Is hand brake active.
<hazard_lights>: <bool>
Are hazard lights active.
<indicators>: <av_indicator_state>
Vehicle turning light indicator state. See definition below.
<brake_pedal_pos>: <float>
Brake position as percentage.
<throttle_pedal_pos>: <float>
Throttle position as percentage.
<steering_wheel_angle>: <angle>
Steering wheel angle.
<siren>: <bool>
Is siren turned on.
<emergency_lights>: <bool>
Are emergency lights turned on.

av_indicator_state is defined as:

av_indicator_state: [indicator_state_unknown, indicator_state_off, indicator_state_left, indicator_state_right]

Description

See Update methods.

validate()

Purpose

Add post-plan validations

Category

Method of any normal scenario

Syntax

extend any_normal_scenario:
    def validate() is empty

Description

validate() is used to validate generated values. In the case of an invalid plan, calling top.replan_error causes a plan retry.

validate() is useful for detecting post-generation limitations, which are hard to model for generation. For example, validate() is used to check that no object is planned to be created in an excluded area (since modeling excluded areas for generation is not a trivial task).

Update methods

The update methods, pre_sim_update(), update_state() and post_sim_update(), are called during state updates from the simulator. The flow is as follows:

  1. Call pre_sim_update() for all of the simulation actors.

  2. Get the updated state from the simulation.

  3. For each actor received from the simulator, call update_state() with the state received from the simulator.

  4. After handling the state of all of the actors, call post_sim_update() for all of the actors.

update_state() should not assume any order, so it should mainly handle the state of the current actor.

post_sim_update() can assume that the state of all of the actors is already updated.