No edit summary
No edit summary
Line 29: Line 29:
** 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).
** 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 ===
=== Base Parameters ===
  "shipping_lane_layers": [ "NS_Shipping_Routes" ],
  "shipping_lane_layers": [ "NS_Shipping_Routes" ],
"country_border_layer": "NS_EEZ",
"shipping_lane_point_merge_distance": 10000,
"shipping_lane_subdivide_distance": 50000,
"shipping_lane_implicit_distance_limit": 200000,
"port_lane_max_merge_distance": 1000,
{| class="wikitable"
{| class="wikitable"
!Field
!Field
Line 36: Line 41:
!Description
!Description
|-
|-
| colspan="1" |shipping_lane_layers
|shipping_lane_layers
| colspan="1" |string[]
|string[]
| colspan="1" |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.
|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",
{| class="wikitable"
!Field
!Type
!Description
|-
|-
|country_border_layer
|country_border_layer
|string
|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.
|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,
{| class="wikitable"
!Field
!Type
!Description
|-
|-
| colspan="1" |shipping_lane_point_merge_distance
| colspan="1" |shipping_lane_point_merge_distance

Revision as of 09:26, 11 April 2024

SEL

The Shipping simulation (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).

Base Parameters

"shipping_lane_layers": [ "NS_Shipping_Routes" ],
"country_border_layer": "NS_EEZ",
"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_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 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.
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

Output Configuration

"output_configuration": {
    "pixels_per_mel_cell": 1,
	"simulation_area_cell_size": 5000
},
Field Type Description
output_configuration object Describes the raster output for SEL
→ pixels_per_mel_cell int Multiplier for the amount of pixels we calculate per MEL cell. If we set this to 4 the resolution will be 4 times what MEL outputs with respect to the bound size. If the bounds of MEL and SEL (playarea) are the same SEL will output at 4x the resolution, if the bounds do not match the resolution is resized proportionally to the bounds of SEL (i.e. we take the bounds, divide the mel_cell_size by this multiplier and apply that over the width and height)
→ simulation_area_cell_size int If MEL is absent you can specify the size of a pixel in the output rasters via this value. This value only applies when MEL is not configured.

Risk heatmap

"risk_heatmap_settings": {
    "restriction_layer_exceptions": [
        "NS_Countries"
    ],
    "shipping_intensity_risk_value": 1000
},

The risk heatmap requires some extra information to work correctly. The risk heatmap works by taking the shipping intensity of the specified ship types. This intensity map is then used as an overlay onto a map of all the specified restriction zones and the intersecting values are plotted onto the result. As an additional result any shipping value over the threshold will be drawn on the riskmap as well.

Field Type Description
risk_heatmap_settings object The "risk_heatmap_settings" block allows you to specify some additional required information for the risk heatmap. This information applies to all heatmaps and specifies which layers need to be excluded from generating the restrictions.
→ restriction_layer_exceptions string[] Specifies the layers which are excluded from generating the restriction map even though they are defined in the restriction matrix.
→ shipping_intensity_risk_value int From this intensity the cell should be marked as a risk zone. So any cells that have a shipping intensity that exceeds this value will be plotted on the resulting risk heatmap.

Heatmap Configuration

"heatmap_settings": [
    {
        "layer_name": "NS_Shipping_Intensity_shipType0",
        "ship_type_ids": [
            0
        ],
        "heatmap_range": [
            {
                "input": 0,
                "output": 0
            },
            {
                "input": 1000,
                "output": 1
            }
        ]
    }
]
Field Type Description
heatmap_settings object[] Definition of all the available heatmaps for the current configuration.
→ output_for_mel bool OPTIONAL: Marks this layer as a layer that should be output to MEL. This will change the raster bounds to match MEL's raster bounds and use the same resolution as MEL

Default: false

→ heatmap_type enum OPTIONAL: Type of heatmap. By default this is "ShippingIntensity". Accepted values: "ShippingIntensity", "Riskmap".

Setting this to "Riskmap" will create a riskmap instead of an intensity map.

→ layer_name string Name of the layer to which the output raster should be associated
→ ship_type_ids int[] The IDs of the ship types that should be included in this heatmap. This can be any number of ship types IDs from just a single ship type to all ship types that are available.
→ heatmap_range object[] Rangemapping of the heatmaps. This field specifies what shipping intensities should map to what colour on the heatmap. This is a sparse mapping of input and output values where the simulation will interpolate between the values where necissary. There can be any number of mapping entries in this array.
→ → input int The input intensity for the mapping
→ → output float Values 0..1. Output colour on the heatmap.
"heatmap_bleed_config": {
    "bleed_number_of_kernels": 5,
    "bleed_treshold": 100,
	"bleed_overflow_curve_power": 0.6,
	"bleed_overflow_curve_multiplier": 1.25
},
Field Type Description
→ bleed_treshold int From what values the bleeding effect should start. This value value represents a maximum intensity on a single pixel. Any raster values that are over bleed_treshold bleed over to neighbouring edges.

Default: 1000

→ bleed_overflow_curve_power float The power of the the function that selects the bleeding kernel. The function for selecting the bleeding kernel is specified as: Round((x ^ bleed_overflow_curve_power) * bleed_overflow_curve_multiplier) where x = percentage of the overflow (Example: maxValue = 1, currentValue = 2, x = 2. maxValue = 1, currentValue = 3, x = 0.5).

Default: 0.6

→ bleed_overflow_curve_multiplier float The multiplier applied to the function that selects the bleeding kernel. See bleed_overflow_curve_power.

Default: 1.25

→ bleed_number_of_kernels int The number of bleeding kernels we generate. Each bleeding kernel will cause a bleed over a larger area, and the size of the bleeding is limited by the biggest kernel. The pixel kernel size is calculated by the formula (3 + (2 * kernelIndex)) and is expressed in pixels. This results in kernel the following sizes: 0 → 3x3, 1 → 5x5, 2 → 7x7, 3 → 9x9, N → (3 + (N * 2)).

Default: 15

Ships

Ship types

"ship_types": [
    {
        "ship_type_id": 1,
        "ship_type_name": "Passenger",
		"ship_routing_type": "RegularShipping",
        "ship_agility": 0.8
    }
]
Field Type Description
ship_types object[] Defines the available ship types in this scenario.
→ ship_type_id int Unique integer based identifier for this specific ship type.
→ ship_type_name string Name of this ship type
→ ship_routing_type enum Accepted values: "RegularShipping", "Maintenance"

Default: "RegularShipping"

Defines how we should populate the routing tables for this ship type.

  • RegularShipping: Your average shipping intensity. Will route according to the configured_routes fields and spread any remaining intensity over all ports that are marked as DefinedPort and accept this ship type.
  • Maintenance: Routing tables will be created for this ship type from every port marked with MaintenanceDestination to the nearest port marked as DefinedPort.
→ ship_agility float Values 0..1. Agility defines the willingness to take shortcuts. The higher the agility the more likely the ship is to take shortcuts. Values close to 0 will take the defined shipping lanes as much as possible, and values of 1 will take the most efficient route available.

Ship type mapping to shipping lane layer types

Use this to let SEL know which ship types are allowed over which shipping lane geometry types. In the example below, the 'Passenger' type is one of the NS_IMO_Routes  layer, while the 'Invisible_Lanes' type is one of the NS_Shipping_Invisible_Lanes layer, and both layers were also defined as shipping_lane_layers.

"layer_type_ship_type_mapping": [
    {
      "layer_type": "Passenger",
      "ship_type_ids": [
        1
      ]
    },
    {
      "layer_type": "Invisible_Lanes",
      "ship_type_ids": [
        1,
        2,
        3,
        4,
        5
      ]
    }
]
Field Type Description
layer_type_ship_type_mapping object[] Maps ship types to shipping lane layer types in this scenario. Requires definition of appropriate ship types (see above).
→ layer_type string Name of any of the shipping_lane_layers' types (referencing 'displayName' under the layer's 'layer_type' definition under 'meta') that should be mapped to one or more ship type IDs. For SEL to be able to find geometry with that type, make sure the layer(s) that use(s) that type have been added to the shipping_lane_layers list (see above).
→ ship_type_ids int[] List of ship type IDs that should be mapped to the particular shipping_lane_layers' type (see above).

KPIs

The calculation of KPIs is at the time of writing (v4.0.1) hard-coded within SEL. As far as I know, only the game client needs this definition, not SEL.

"shipping_kpi_config": [
    {
      "categoryName": "General",
      "categoryColor": "#00FF00FF",
      "unit": "ship",
      "generateValuesPerPort": null,
      "categoryValueType": "Sum",
      "valueDefinitions": [
        {
          "valueName": "ShippingIntensity",
          "valueColor": "#00FF00FF",
          "unit": null,
          "valueDependentCountry": 0
        },
        {
          "valueName": "ShippingRisk",
          "valueColor": "#00FF00FF",
          "unit": null,
          "valueDependentCountry": 0
        }
      ]
    },
    {
      "categoryName": "Route Efficiency",
      "categoryColor": "#00FFFFFF",
      "unit": "%",
      "generateValuesPerPort": "ShippingRouteEfficiency_",
      "categoryValueType": "Average",
      "valueDefinitions": null
    }
]
Field Type Description
shipping_kpi_config object[] Defines the shipping key performance indicators (KPIs) that should be calculated and stored after each month run for this scenario.
→ categoryName string Name of the category of KPIs you are defining, used by the client for grouping.
→ categoryColor string Hexadecimal colour code (with the last two digits representing transparency) for said category, used by the client when KPIs under this category are selected for graph drawing.
→ unit string Unit of measurement that should be shown next to the actual KPI value. Currently not used as SEL has hard-coded units of measurement, and in turn the client gets this from the session database (and thus through the websocket service).
→ generateValuesPerPort string Nullable. If not null, then this indicates that the KPI should be calculated per port, as defined under port_layers. Currently not used as SEL has hard-coded KPI calculations.
→ categoryValueType string Stipulates how to calculate the KPI in question. Currently this has been set to Sum or Average. The SEL code doesn't do anything with this currently.
→ valueDefinitions object[] Any specific value groupings for a particular KPI category. Currently only in use for the general (so non-port-specific) KPIs.
→→ valueName string Name of the KPI value falling under this category, used by the client to know what KPI to actually pick up and show.
→→ valueColor string Hexadecimal colour code (with the last two digits representing transparency) for said value of the KPI falling under the category at hand, used by the client when this KPI is selected for graph drawing.
→→ unit string Nullable. If not null, then it overrides the category wide unit of measurement. (untested)
→→ valueDependentCountry int 0 or the country ID of a specific country defined as one of the types of the layer defined under 'countries' (thus representing the countries data layer). Currently not implemented, as far as I can tell.
This page was last edited on 11 April 2024, at 09:26. Content is available under GPLv3 unless otherwise noted.