Skip to content

Map Lanes

Map raw rows into the scenario's lanes table: the set of routes Network Optimization is allowed to ship on, with the per-unit cost of each.

Lanes are required for Network Optimization. Without them the optimizer has nothing to route through, and the run stops.

When to use this

  • You're building a scenario that will be optimized
  • You want the optimizer to consider routes that were not used in historical shipments. That is how it discovers new sourcing
  • You need per-mode alternatives (FTL vs LTL, ocean FCL vs LCL) on the same origin-destination pair

What you need

  • An upstream Import Data node carrying one row per lane, or one row per origin-destination-mode combination
  • Origin and destination columns whose values match identifiers in the locations table
  • A per-unit cost on each lane. Network Optimization refuses a lane with no cost, naming its rows; write 0 for a move that really is free

Field mapping

Fields are matched by name unless you set them. When the workflow runs, every field you have not set a column for is matched against the headers listed below, case-insensitively and ignoring spaces around the header, and a space inside your header reads as an underscore, so Site Name matches site_name. Setting a column for one field fixes that field only; the others keep following your file's headers, so a renamed column is still found. A required field that no column supplies — no header matched, or you set none or one your table lacks — is reported once, with the headers your table does have.

Set mappings in the node's panel. Connect an upstream table and select the mapping node. A field matched by name is marked Matched by name; pick a column to set it yourself, and Match by name puts it back. Match all by name clears every field you set. Required fields without a match are marked in the panel.

Reshape rows in a Script first. A mapping node only says which column is which field. To drop rows, recode values, or split or combine columns, connect a Script node before it and map the columns the Script returns.

Same for every row. A file with no unit column still states its unit: in Quantity Unit, pick Same for every row and type the unit, such as pallets, and every row is in it. Over MCP, set it in field_mappings as "quantity_unit": "__const__:pallets". Quantity Unit is required on every row with Unit Cost, Capacity, Emissions per Unit or Minimum Quantity, and the panel marks it required once one of those is mapped.

Field Type Required Example What it is Auto-detected headers
Source text Yes Warehouse A Origin location name source, from, origin, source_id, from_id
Target text Yes Store 1 Destination location name target, to, destination, dest, target_id, to_id
Product text Yes Widget The product this lane carries; a filter over products, such as "Chilled" in product.tags or product.product_group == "Chilled", for a lane open to each product it matches; or ALL, for a lane open to every product. A filter or ALL row's unit cost, lead time and emissions apply to each of its products, and a row naming one product refines that product's terms on the same source, target and transport mode. Two rows for the same product there, or two filter or ALL rows sharing a product, are refused. Any other value must match a Product name. product, sku, item, material, product_id
Unit Cost number No 5.0 Cost per unit shipped, per the lane's Quantity Unit. Must be greater than or equal to 0. unit_cost, cost_per_unit, rate, freight_rate, transport_rate
Capacity number No 1000.0 Maximum flow allowed on this lane. On a product filter or ALL lane this bounds the combined flow of its products in the lane's Quantity Unit, each product weighed by its own conversion, separately per transport mode, including products that have a row of their own. Zero closes the lane; blank = unlimited. Must be greater than or equal to 0. Its unit goes in Quantity Unit. capacity, max_flow, max_quantity, max_volume, quantity
Lead Time number No 2.0 Transit time in days. Must be greater than or equal to 0. lead_time, transit_time, days, transit_days
Emissions per Unit number No 0.5 Emissions per unit shipped, in the scenario's emissions unit, set on Create Scenario. Must be greater than or equal to 0. emissions_per_unit, co2_per_unit, carbon_per_unit, emission_rate
Transport Mode text Yes FTL Transport mode (e.g., FTL, LTL, rail, ocean, air). Required — name it even in a network with one mode. transport_mode, mode, shipping_mode, carrier_type, shipment_mode, transport_type
Minimum Quantity number No 20.0 Minimum shipment quantity when this lane is used (e.g., FTL threshold). On a product filter or ALL lane this applies to the combined flow of its products on the same source, target and transport mode, including products that have a row of their own. Must be greater than or equal to 0. Its unit goes in Quantity Unit. min_quantity, min_qty, minimum_quantity, min_shipment, minimum_qty, min_order
Quantity Unit text No pallets Unit the lane's capacity, minimum quantity, cost per unit and emissions per unit are in. Required on every lane that carries one. A unit other than the scenario's needs a conversion for each product the lane carries. quantity_unit, qty_unit, unit, uom

Lanes compared with flows

lanes (Map Lanes) flows (Map Transport)
What it represents What routing is allowed, and at what cost What actually flowed
Required for Network Optimization Yes No
Cost Per unit Realized total, and optionally per unit

How it works

Each row becomes a lane record on the scenario. Network Optimization reads them as the set of routes it may use. Include every route you want considered, even ones not used in historical data. If you only have historical shipments, build a lanes table from your location pairs first. Distance-based per-unit costs are a reasonable starting point.

For consolidation-versus-direct decisions, give the same origin-destination pair several rows, one per transport mode, and set Minimum Quantity on the full-load modes. The optimizer then picks FTL or FCL only when volume justifies it.

Emissions per Unit is in the scenario's one emissions unit, the Emissions Unit set on Create Scenario. A scenario whose lanes carry emissions without that setting is refused. Create Scenario stores its unit with every lane carrying emissions. Map the rate only; an emissions unit column is not mapped, and nothing is converted.

Lanes for several products

Product on a lane takes one of three things:

  • a product, for a lane that carries that product only
  • a filter over products, for a lane that carries each product the filter matches and nothing else, such as product.product_group == "Chilled" for every product whose Product Group is Chilled, or "Key Wines" in product.tags for every product tagged Key Wines. The filter is written as in an Add Constraint rule, with product as its only name, and reads the products' name, Product Group, description and Tags from Map Products
  • ALL, for a lane that carries every product

A filter that cannot be read, or that matches none of the scenario's products, is refused by Create Scenario, naming the rows. A cell such as All Chilled, written for earlier versions, is not a product and is refused with a hint to write product.product_group == "Chilled" instead. The filter is read against the products each time the scenario is built, so a product added to the Product Group or given the tag later is carried too.

On a filter or ALL lane, Unit Cost, Lead Time and Emissions per Unit apply to each product it carries. Capacity and Minimum Quantity apply to the products' combined flow on that origin, destination and transport mode, as on one truck: a reefer lane for product.product_group == "Chilled" with a capacity of 1,000 carries at most 1,000 chilled units in total, in whatever mix. Stated in a unit other than the scenario's, such as pallets, the combined limit weighs each product by its own conversion to that unit.

A row naming one product is more specific than a filter or ALL row on the same origin, destination and transport mode. It sets that product's own cost, lead time and emissions there, and the filter row's combined capacity and minimum quantity still count that product's flow.

Each product on a connection takes its terms from one row, so two rows that would both set them are refused, naming both rows:

  • two rows for the same product, origin, destination and transport mode
  • two filter rows that match a common product, or a filter row and an ALL row, on the same origin, destination and transport mode

To give one product of a filter row different terms, add a row naming that product rather than a second filter.

Every lane names its Transport Mode, even in a network with one mode, and its Product, or ALL. A lane with either blank is refused: it would be a way to ship that no constraint, cost or result on a mode or product reaches.

A lane whose origin and destination are the same location is refused too: it moves nothing, so no cost or quantity on it would mean anything.

Workflow wiring

flowchart LR
    n1["Import Data (locations.csv)"] --> n2["Map Locations"]
    n3["Import Data (lanes.csv)"] --> n4["Map Lanes"]
    n4 --> n5["Create Scenario"]
    n5 --> n6["Network Optimization"]
    n6 --> n13["Create Scenario"]
    n7["Import Data (supply.csv)"] --> n8["Map Supply Policy"]
    n9["Import Data (demand.csv)"] --> n10["Map Demand Policy"]
    n2 --> n5
    n8 --> n5
    n10 --> n5
    n11["Import Data (products.csv)"] --> n12["Map Products"]
    n12 --> n5

Common mistakes

  • Skipping Map Lanes when only shipment history is available. Network Optimization rejects the scenario. Build lanes from your origin-destination pairs instead.
  • Forgetting the unit cost. Network Optimization refuses a lane without one rather than read it as free.
  • Putting realized totals on Unit Cost. It is per unit. The realized total of an observed flow belongs on Map Transport.
  • Copying a lane once per product to cover a class of products. Write one row with a filter instead, such as product.product_group == "Chilled", so a product added to that class later is carried too.

Messages this node can show

The table this node makes is checked again with the rest of the scenario when Create Scenario assembles it: see messages about the scenario.

A run gives this node 5 minutes. A node that takes longer stops with Time limit reached.

Like every node, it can also stop on the checks before a run and the run's limits.