Network Optimization
Find the cheapest way to run your network: where each customer is served from, which routes carry the volume, and how much each site handles or makes.
When to use this¶
- Sourcing — decide which supplier or plant serves which customer, and compare the result with how you source today
- Routing — find the cheapest routes through the network, including routes you have never used, by giving the optimizer every lane it may consider
- Warehouse footprint — see which sites carry volume once each is capped by a throughput limit, and choose which optional sites to open using fixed operating costs from Map Location Policy
- Production allocation — when your network makes products, decide how much to produce where, with bills of materials and plant capacity respected
- Cost against emissions — rerun the same network with Set Objective minimizing emissions, or weighing the two, and read the trade-off off the two scenarios
- What-if under a rule — cap a lane, keep a minimum on a full-truck lane, or fix a flow with Add Constraint, and see what the rest of the network does around it
- Partial service — decide whether serving every order is worth it when supply is short, by allowing partial fulfilment and reading which demand goes unserved
What you need¶
Three tables in the scenario. Without any one of them the run stops and says which:
- Lanes, from Map Lanes — the routes the optimizer may ship on, each with its per-unit cost
- Supply policy, from Map Supply Policy — where units can be sourced, at what cost and up to what capacity
- Demand policy, from Map Demand Policy — what must be served, and what serving it earns
Handling cost, from Map Handling Policy, is optional and changes the answer when it is there. Production data, from Map Bill of Materials and Map Production Policy, adds production decisions.
Settings¶
| Setting | Default | What it does |
|---|---|---|
| Allow partial demand fulfillment | off | Off, every demand point must be fully served or the run fails. On, the optimizer serves as much demand as is profitable and reports what it left unserved. |
| Debug mode | off | When a run is infeasible, adds slack so the result names the constraints that could not be met. |
| Solver time budget (seconds) | 7200 |
The longest the solver may run. A solve that reaches it stops there and keeps the best solution found so far. Between 60 seconds and eight hours; asking for more than the service allows is refused before the run starts, and the run's record shows what was asked and what was granted. |
A node you have never opened runs with the defaults above; the panel writes nothing into a node until you change something on it.
Set the partial-demand box deliberately the first time you open the panel. Changing anything on the panel writes both checkboxes, and the box draws itself ticked on a node that carries no value — so on a fresh node, the first change you make turns partial demand on, whatever you were trying to change.
The default objective maximizes profit, which minimizes cost while meeting demand. To optimize for emissions instead, or to balance the two, wire a Set Objective node in front of this one.
When every supplier has a capped supply and total supply is below total demand, the run fails. Turning Allow partial demand fulfillment on softens that: the optimizer then serves what it profitably can instead of failing. Otherwise cap fewer suppliers, or raise the caps. A supplier with no cap is unlimited, so this only bites when every connected supplier is capped.
What you get¶
An optimized scenario with the flows, sourcing and production the optimizer chose, plus the objective value for the optimized total. Compare it with the scenario you started from to see what changed. Results are saved with the scenario when the node runs in a workflow.
Lanes¶
The lanes table is the set of routes the optimizer may ship on. Include every route you want considered, including ones your history never used: that is how the optimizer discovers new sourcing options. If you have only historical shipments and no candidate lanes, build a lanes table from your location pairs, for example with distance-based unit costs.
Site decisions¶
Add Map Location Policy to define sites as include (forced open),
consider (optimizer decides) or exclude (closed). Open sites pay their fixed
operating cost once per planning period, even when idle; closed sites have no
activity. The decision is shared across all products and production recipes.
An absent policy preserves availability with no modeled fixed cost. All costs
must cover the same period as demand. Opening investments and closure charges
are outside this single-period model.
Location state reports open status and incurred fixed cost for sites with a policy. Without site policy, optimization adds no site policy or state table. The scenario reports Total fixed operating cost separately and includes it in Modeled operating cost. Cost and weighted objectives and total-cost budgets include the charge. An emissions-only objective still reports costs, but does not minimize them. Cost to Serve does not allocate site fixed costs.
Handling costs¶
When the scenario carries handling costs, the optimizer folds per-unit facility costs into the total it is minimizing. A product-specific rate takes precedence over a location-wide one. Handling cost can flip a routing decision: a high rate at a hub may make direct shipment cheaper than routing through it.
Changing the objective¶
Wire a Set Objective node between Create Scenario and this one to change what the solve optimizes for. It applies automatically; there is nothing to configure here.
Adding business rules¶
Wire one or more Add Constraint nodes the same way, between Create Scenario and this one, to cap a lane, floor a supplier count, or bound the budget. Each appends a rule the solve respects; the rules are listed on that node's page. A rule that matches nothing in the scenario is reported here as a constraint that matches no arcs, and a rule with a missing parameter as invalid constraint parameters.
Workflow wiring¶
This node takes scenario data. Wire it after Create Scenario, Load Scenario, or Set Objective, never straight after a Map node.
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"]
n7["Import Data (supply.csv)"] --> n8["Map Supply Policy"]
n9["Import Data (demand.csv)"] --> n10["Map Demand Policy"]
n2 --> n5
n8 --> n5
n10 --> n5
Transport flows from Map Transport are optional observation data and can be wired into the same Create Scenario.
Starting from a baseline¶
When you start from an existing scenario, the optimizer needs per-unit cost and revenue rates on the policy tables: supply, demand, lanes and handling. A baseline built from observed history carries realized totals instead. Those record what happened; they are not the rates the optimizer uses to decide what should happen.
Feeding such a baseline straight in does not give an answer you can use:
- A missing supply cost stops the run. Priced at zero, that supplier would look free and the optimizer would source everything from it.
- A missing unit revenue stops the run when partial demand is allowed, because at zero revenue no order is worth serving. With partial demand off, which is the default, the run proceeds and only the reported objective is understated.
- Missing lane and handling rates are priced at zero, so those routes look free and get over-used.
The fix is to derive the per-unit rates from the observed history first, with a chain of Scenario Script steps:
flowchart LR
n1["Load Scenario"] --> n2["Scenario Script (derive supply rates, into Scenario Data)"]
n2 --> n3["Scenario Script (derive demand rates, into Scenario Data)"]
n3 --> n4["Network Optimization"]
n4 --> n5["Create Scenario"]
Each step writes the per-unit rate as a weighted average over the observed history. Where the baseline has no cost data at all for a concept, the rate is left empty and the run says so. That is a gap in your baseline, and naming it beats quietly pricing the cost at zero.
Common mistakes¶
- Wiring this node to a Map node instead of through Create Scenario
- Missing the lanes table, or missing cost data on lanes or supply records
- Leaving out either Map Supply Policy or Map Demand Policy — each is a refusal on its own
- Loading a baseline and optimizing without first deriving per-unit rates — baselines built from observed history are usually missing them