9.2 Formatting ASAM OpenSCENARIO code

9.2.1 Coding style guide

This coding style guide is intended to help you write source code in the ASAM OpenSCENARIO domain-specific language in a uniform way.

9.2.1.1 Introduction

This guide focuses on uniform formatting and naming for source code. It does not contain best practices nor is it a reference for the language.

You should follow the recommendations in this document if you are a scenario developer writing scenarios for real use.

By following the recommendations in this guide the code becomes easy to understand for you and other users.

9.2.2 Formatting

9.2.2.1 Indentation

  • Use four space characters per indentation level.

  • Do not use tab characters.

  • Use the following text editor settings:

    • Tab size: 4

    • Insert spaces

9.2.2.2 Encoding

  • Use UTF-8 as encoding.

9.2.2.3 Whitespace

Whitespace characters provide better readability when used in the correct places.

The correct use of space characters within ASAM OpenSCENARIO source code is as follows:

  • One space after a comma (in argument lists and other lists)

  • One space after a colon (for example for inheritance)

  • One space before and after a keyword

  • One space before and after an operator

  • No spaces before and after brackets and braces (for example, in function calls or for indexing)

  • No space between value and unit

The following code snippet shows some examples of the correct use of space characters.

Code 83. Correct use of space characters
func(arg[1], arg2)
if x == 4: print x, y
foo == [x, y, z]
func(1)
abc[key] = lst[index]
i = i + 1
actor bus: car(category: bus):
   keep(width == 1.8m)
   keep(length == 4.5m)

swerve_story: serial:
    side_vehicle.drive() with:
        path(s_side_vehicle)
        keep_speed()
    with:
        until (top.time > 5sec)

9.2.2.4 Comments

  • Single lines of comments and inline comments can be added using the 'pound' symbol (#).

    # This is a single line comment.
    i = i + 42  # This is an inline comment
  • Blocks of comments can be simulated by using several single lines of comments.

    # This is a block of comments example.
    # The following call to foo is commented out
    # Reason: see issue xyz
    # More explanation here...
    #
    # foo()

9.2.2.5 Line breaks

  • Consider breaking up statements that are too long to fit into one line.
    Use the line continuation special character 'backslash' (\) for marking the continuation.

    This is a line of text that is too long for a single \
    line, so continue after the backslash in a new line.

9.2.3 Naming

Naming conventions are a widely discussed topic with great influence on readability influenced by fashion changes, habit, and personal taste.

Here are the recommendations valid for naming conventions in ASAM OpenSCENARIO source code.

9.2.3.1. Use snake_case only

  • Use snake_case (aka lowercase_with_underscore) for all source code elements that are not keywords.

Code 84. Example for correctly formatted code
# 1: Define an actor
actor car_group:
     average_distance: length
     number_of_cars: uint

# 2: Define a road element struct
struct geometric_road: road_element:
    min_radius: length
    max_radius: length
    side: av_side

# 3: Define a scenario
scenario dut.traverse_junction_at_yield:
    s: road_with_sign with(sign_type: yield)
    do dut.car.traverse_junction() with: ...

# 4: Define a containing scenario
scenario dut.mix_three_dangers:
     weather_kind: weather_kind
     keep(weather_kind != clear)
     do mix:
         cut_in_and_slow()
         traverse_junction_at_yield()
         weather(kind: weather_kind)

9.2.3.2 Single character names

Do not use the following characters as single character names because they can be easily misread as zero (0) or one (1):

  • No single lowercase 'el' (l)

  • No single uppercase 'eye' (I)

  • No single lowercase 'oh' (o)

  • No single uppercase 'oh' (O)

9.2.4 Example

Here is a more complex example showing all the rules.

Code 85. Example for correctly formatted code in ASAM OpenSCENARIO
scenario slower_large_vehicle_in_adjacent_lane
    ego_vehicle: vehicle with:
        keep(p_vehicle_model == APTIV_ego_vehicle)
    v1: vehicle with:
        keep(vehicle_category == Bus)
        keep(p_vehicle_model == BlueBird_Vision_2014)
        keep(p_vehicle_model.Color == Blue)

    ego_model: ego_vehicle.p_vehicle_model
    ego_route: ego_vehicle.route
    v1_model: v1.p_vehicle_model
    v1_route: v1.route

    ego_start_speed: speed
    ego_start_distance: length
    v1_start_speed: speed
    v1_start_distance: length

    simulation_platform_choice: string
    simulation_time_threshold_reached: time
    ego_ttc_threshold: time
    ego_distance_to_bias: length
    lane_choice: string
    ego_lane: lane
    map: file_path

    keep(map == "/maps/example.xodr")

    simple_3_lane_road_01: lane_section
    lane1^: lane
    lane2^: lane
    lane3^: lane

    simple_3_lane_road_01.lanes = [lane1^, lane2^, lane3^]
    keep(simple_2_lane_road_01 == map.road(id:"1").*lane_section(s:"0"))
    lane3^ = rightmost_lane(map.*right)
    keep(lane2^ -[:LEFT_OF]-> lane3^)
    keep(lane1^ -[:LEFT_OF]-> lane2^)

    # Logic parameter syntax
    keep(ego_lane in: { if: lane_choice == "Left" THEN: SET ego_lane = "lane1^",
                        if: lane_choice == "Right" THEN: SET ego_lane = "lane3^"})

    keep(ego_model == APTIV_ego_vehicle)
    keep(ego_route == ego_drive_left)
    keep(v1_model == BlueBird_Vision_2014)
    keep(v1_route == v1_drive)

    keep(ego_start_speed == 80.46719999999999 [kph])
    keep(ego_start_distance == 5 [m])
    keep(v1_start_speed == 48.28032 [kph])
    keep(v1_start_distance == 55.0 [m])

    keep(simulation_platform_choice == "CarMaker")
    keep(simulation_time_threshold_reached == 120 [s])
    keep(ego_ttc_threshold == 1 [s])
    keep(ego_distance_to_bias == 1 [m])
    keep(lane_choice == "Left")

    # Relationship syntax
    keep(v1_start_speed -[:SLOWER_THAN]-> ego_start_speed)

    def distance_between_ego_vehicle_and_v1(vehicle, vehicle) -> length is external "kpi.py"
    def get_ttc_with_vehicle_to_vehicle(vehicle, vehicle, string) -> time is external "kpi_TTC.py"

    !ego_speed: speed = ego_vehicle.speed
    !ego_end_of_road: Position = ego_vehicle.end_of_road
    !ego_off_road: Position = ego_vehicle.off_road
    !simulation_time: time = simulation.time
    !ego_vehicle_lane: lane = ego_vehicle.lane
    !ego_collision_monitor: integer = sensor.collision.v.fr1.count

    !ego_ttc_with_v1: time = sample(ego_vehicle.get_ttc_with_vehicle_to_vehicle(ego_vehicle:vehicle, v1:vehicle, [simulation_platform_choice]))
    !ego_distance_to_v1: length = sample(distance_between_egoVehicle_and_v1(v1:vehicle, ego_vehicle:vehicle, [simulation_platform_choice]))

    event observation_complete is(one_of(@end_conditions))

    event ego_ttc_threshold_reached1 is(!ego_ttc_with_v1 < ego_ttc_threshold)
    event ego_close_to_v1 is(!ego_distance_to_v1 < ego_distance_to_bias)

    event end_conditions[1] is(!ego_end_of_road > 0)
    event end_conditions[2] is(!ego_off_road > 0)
    event end_conditions[3] is(!simulation_time > [simulation_time_threshold_reached])
    event end_conditions[4] is(!ego_collision_monitor > 0)
    event end_conditions[5] is((ego_vehicle.s_road - v1.s_road) > 40)

    do parallel():
        ego_init_drive_01: ego_vehicle.drive(ego_route) with:
            position(at_distance: ego_start_distance, beyond_start_of: ego_route)
            speed(at_speed: ego_start_speed)
            at(at:start)
        v1_init_drive_01: v1.drive(v1_route) with:
            position(at_distance: v1_start_distance, ahead_of: ego_vehicle)
            speed(at_speed: v1_start_speed)
            at(at:start)
            until(@observation_complete)

If you cannot find a recommendation for your source code formatting or naming problem in this chapter, follow the Style Guide for Python Code (PEP 8).