SEL

A brief explanation of the Shipping Model (SEL) config. SEL can be almost completely configured within the config file for the scenario. All fields in this document are attached to the 'SEL' object of the config file, unless explicitly said otherwise.

The characteristics of SEL's pathfinding logic are explained in the conference paper listed on the Research Publications page. Something more specific to add to that paper concerns the exact configuration options with which you can control pathfinding.

Always keep in mind that SEL ideally finds straight lines between port of origin and port of destination (as ship captains in real life also would like to do), but that there are always things influencing / altering that straight line:

  • Things that disallow a route from going through there, e.g. a real restriction - an island, a wind farm, a no-shipping zone, ... To configure something like this, just add the data layer as a restriction, see the first instructions explained further below under 'Restrictions'.
  • Things that (strongly) encourage a route to go through there rather than just around it or slightly to the left or right from it, such as an IMO route. To configure something like this, just add the data layers as a shipping_lane_layers as explained under 'General' immediately below.
  • Things that (strongly) discourage a route to go through there, e.g. shallow areas. To configure something like this, add the data layer as a restriction, and then again as a restriction exception to set a cost / penalty, as explained under 'Restrictions' too.

Common practices in e.g. the North Sea or Baltic Sea configs is to use the above system as follows:

  • Make a vector version of bathymetry layer with which to discourage SEL to go through shallow waters, i.e. ...
    • This means turning the bathymetry raster into a bathymetry polygon layer, based on above or below ~20m depth only.
    • and then adding that new bathymetry vector layer to the config file, but making it invisible by setting layer_active, layer_selectable, layer_editable, layer_toggleable, and layer_active_on_start to 0 in the layer's definition under 'meta',
    • and finally adding the layer to the 'restrictions' definition (outside of the 'SEL' object in the config file) as well as the 'restriction_exceptions' definition (back inside the 'SEL' object again). See the 'Restrictions' section further below for more information and an example.
  • Make an 'invisible shipping lanes' layer with which to encourage SEL to use certain common routes that don't involve e.g. any IMO lanes or something else, i.e., ...
    • a layer of lines in areas that SEL tends to avoid even though they are in real life commonly used,
    • making that layer again invisible to players (see above)
    • and finally adding the layer to shipping_lane_layers. Note that you can also set ship_types and then map this layer's types to those ship types using layer_type_ship_type_mapping (see below).
  • Make a 'connection points' layer to help SEL find paths around areas that disallow it to use, e.g. when a port of destination is 'hiding' behind a bit of land from the perspective of the port of origin (e.g. an island or peninsula), i.e., ...
    • a layer of points equally spaced, e.g. every 5 kilometers apart, horizontally and vertically, up until the shorelines, a perhaps some more going up a river
    • making that layer again invisible to players (see above)
    • and finally adding the layer to shipping_lane_layers. Note that you can also set ship_types and then map this layer's types to those ship types using layer_type_ship_type_mapping (see below).
  • Make a 'fairways' layer to help SEL find paths up an estuary (or other land-locked, narrow bits), as an alternative for adding a big bunch of connection points (see previous point), i.e., ...
    • a layer of lines, could actually be lines that are dredged in real life to ensure deep enough entrances into big ports for container or tanker vessels for example
    • you could decide to keep this layer visible and editable for players. We did that with the Baltic Sea config.
    • and finally adding the layer to shipping_lane_layers. Note that you can also set ship_types and then map this layer's types to those ship types using layer_type_ship_type_mapping (see below).

General

"shipping_lane_layers": [ "NS_Shipping_Routes" ],
Field Type Description
shipping_lane_layers string[] The "shipping_lane_layers" specify what layers define the geometry for the shipping lanes. There needs to be at least one layer defined for the shipping model to work correctly, but any number of additional layers can be defined as an array.
"country_border_layer": "NS_EEZ",
Field Type Description
country_border_layer string Layer which defines the area of each country. This was required for figuring out what country each port belongs to in order to correctly submit the KPI values.

Regional Config Settings

"shipping_lane_point_merge_distance": 10000,
"shipping_lane_subdivide_distance": 50000,
"shipping_lane_implicit_distance_limit": 200000,
"port_lane_max_merge_distance": 1000,
Field Type Description
shipping_lane_point_merge_distance double Merge distance for simplification. All nodes on a single geometry instance will be merged if their distance to the previous node is lower than this value
shipping_lane_subdivide_distance double Edges in defined geometry will be subdivided across this length so we have segments that are approximately this length.
shipping_lane_implicit_distance_limit double Maximum distance we consider for creating implicit edges.
port_lane_max_merge_distance double Distance at which ports can be merged / connected to shipping lane vertices. Shipping ports on land can only create new connections through this merge method.

Ports

Definitions

"port_layers": [
    {
        "layer_name": "BS_Ports_Model",
        "port_type": "DefinedPort"
    },
    {
        "layer_name": "BS_Wind_Farms_Edit",
        "port_type": "MaintenanceDestination"
    }
],
Field Type Description
port_layers object[] Collection of layers that hold the shipping port geometry.
→ layer_name string The layer_name field defines the name of the layer which hold the geometry for the ports.
→ port_type enum Accepted Values: "DefinedPort", "MaintenanceDestination"
  • DefinedPort: All regular ports layer should be marked with this. DefinedPorts will emit and accept intensity based on the configured intensities in the config file. For these ports KPIs will be calculated based on the shipping_kpi_config setup (see further below). NOTE: All geometry in a layer marked as a DefinedPort is expected to have a "name" field in the geometry_data, so in the geometry's data table. Any "name" values with non-English 'special' characters are unfortunately at present not supported, so any language-specific characters must be converted into English alphabet characters. E.g. Göteborg > Goteborg or Florø > Floro.
  • MaintenanceDestination: These ports will emit ship types that are marked with the Maintenance routing type. Intensities are based on the area and the maintenance_destination configuration in the SEL region settings.

Intensities

"port_intensity": [
    {
        "port_id": "Port0",
        "ship_intensity_values": [
            {
                "start_time": 0,
                "ship_type_id": 0,
                "ship_intensity": 500
            },
            {
                "start_time": 10,
                "ship_type_id": 0,
                "ship_intensity": 1000
            }
        ]
    }
]
Field Type Description
port_intensity object[] Description of the port intensities per port
→ port_id string Persistent identifier of the ports we are going to specify the intensity for.
→ ship_intensity_values object[] Array of intensity per ship type and per time
→→ start_time int Month at which this intensity should be in full effect
→→ ship_type_id int The unique ID of the ship type we are defining the intensity for
→→ ship_intensity int The intensity value at the specified time and for the specified ID on the port. Intensities will be linearly interpolated in the months that are not defined. So for our example config month 5 will result in 750 intensity. Month 11 will result in 1000 intensity.

Maintenance destinations and intensities

"maintenance_destinations": {
    "construction_intensity_multiplier": 2.5,
    "base_intensity_per_square_km": 1,
	"point_construction_intensity": 10,
	"point_intensity": 2,
},
Field Type Description
maintenance_destinations object Object describing the intensities for ports that are marked with the MaintenanceDestination type
→ construction_intensity_multiplier float Multiplier for intensity when a port is still in construction. (In our case this means in an Approved plan when game time is the implementation date - assembly time)
→ base_intensity_per_square_km float Intensity multiplier that is applied to the square km area of the polygon. This defines the intensity of the port when the layer is fully constructed and active.
→ point_construction_intensity float Intensity per month for point geometry while the geometry is sitll being constructed.
→ point_intensity float Intensity per month for point geometry that are marked as maintenance destinations.

Preconfigured Routes

"configured_routes": [
    {
        "source_port_id": "Port1",
        "destination_port_id": "Port0",
        "ship_type_id": 4,
        "intensity_percentage": 1
    }
]
Field Type Description
configured_routes object[] An array of preconfigured routes and their relative intensities
→ source_port_id string ID of the port that the route starts
→ destination_port_id string ID of the port that the route ends
→ ship_type_id int ID of the ship type that should take this route
→ intensity_percentage float Values 0..1. The percentage of ships that are generated on source_port that should take this route. Any ship that is not allocated via a preconfigured route will be distributed over all the other available ports depending on their intensities. Ports that have a higher intensity will be sent more ships.
→ start_time int OPTIONAL: the month from when the route should become active. The simulation will always take the route that has the most recent start_time if there's multiple routes defined for the same source, destination and ship type id.

Restrictions

The system uses the restrictions setup in the config file which intersect with the shipping lane layers. This means that SEL looks at the 'restrictions' object in the config file (so outside of the SEL section!) to find the geometry of layers mentioned in there as being restricted by layers defined under SEL's 'shipping_lane_layers'.

So for example, in the North Sea Basic config of v4.0.1, you'll find this restriction definition:

"NS_IMO_Routes|NS_Countries": [
    {
      "message": "Shipping routes should not cross over land.",
      "value": 0.0,
      "type": "WARNING",
      "startlayer": "NS_IMO_Routes",
      "starttype": "",
      "endlayer": "NS_Countries",
      "endtype": "",
      "sort": "Inclusion"
    }
  ],

Notice the 'startlayer' of NS_IMO_Routes and the 'endlayer' of NS_Countries. The NS_IMO_Routes layer is defined as a shipping lane layer:

"shipping_lane_layers": [
    "NS_IMO_Routes",
    "NS_Connection_Points_25km_2",
    "NS_National_shipping_lanes",
    "NS_Shipping_Invisible_Lanes"
],

Because of this, SEL picks up all the geometry under the NS_Countries layer and considers that as something that cannot be crossed when it tries to find the shipping paths.

Here's another example of a restriction definition in the north Sea Basic config of v4.0.1:

"NS_IMO_Routes|NS_Bat_20_shipping": [
    {
      "message": "Bathymetry under 20m is not ideal for shipping.",
      "value": 0.0,
      "type": "INFO",
      "startlayer": "NS_IMO_Routes",
      "starttype": "",
      "endlayer": "NS_Bat_20_shipping",
      "endtype": "",
      "sort": "Inclusion"
    }
],

Again, SEL picks this up too, because NS_IMO_Routes is a shipping lane layer. So SEL also picks up all the geometry of NS_Bat_20_shipping and considers that as something that cannot be crossed when it tries to find the shipping paths.

So SEL doesn't care if the shipping lane layer in the restriction was defined under 'startlayer' or 'endlayer', and it also doesn't care about the 'type' of restriction (warning, info, error, doesn't matter), or the 'value', or 'sort'. All of that doesn't matter.

For exceptions to the shipping restriction layers and their geometry, SEL looks at the next object: 'restriction_layer_exceptions'.

Here's an example of an exception involving that same NS_Bat_20_shipping layer:

"restriction_layer_exceptions": [
    {
      "layer_name": "NS_Bat_20_shipping",
      "layer_types": [
        "default"
      ],
      "allowed_ships": [
        {
          "ship_type_ids": [
            1,
            2,
            3,
            4,
            5
          ],
          "cost_multiplier": 20.0
        }
      ]
    }
]

Have a look at the definitions of the values below. As you can see, by adding NS_Bat_20_shipping as an exception for basically all ship types (IDs 1-5), all of a sudden ships are allowed into the geometry of that layer again when SEL wants to calculate its routes, except that doing so makes it expensive, so SEL will first look for alternatives before it does that. This is exactly the kind of behaviour we want when it concerns shallow waters (which is what the NS_Bat_20_shipping geometry depicts).

Field Type Description
restriction_layer_exceptions object[] Restriction layer exceptions define what exceptions there are to the restrictions to allow certain ship types to move over certain layer types.
→ layer_name string The name of the layer this exception applies to
→ layer_types string[] The types within the layer the exception applies to. Each corresponds to the 'displayName' of a specific layer_type of a layers as defined under 'meta' outside of the SEL config.
→ allowed_ships an array of allowed ships (containing the ID, and the Cost multiplier) can be created for more flexible use of the system

so Type 1,2,3 can have a multiplier of 1

and Type 4,5 can have a multiplier of 20

→ →

ship_type_ids

int[] IDs of the ship restriction groups that should be allowed to cross over the layer and type defined.
→ → cost_multiplier float Cost multiplier traveling over an edge that is affected by this exception. This can be used to make routes more costly that go over these areas while not blocking them off completely.

Defaults to 1.0.

Heatmaps

This page was last edited on 8 April 2024, at 14:44. Content is available under GPLv3 unless otherwise noted.