Map Demand Policy
Map raw rows into the scenario's demand policy table: the rules for demand at each location, how much is requested, and what each fulfilled unit earns.
This is the input side of demand. Pair it with Map Demand State when you also need to preserve what was fulfilled in a baseline.
When to use this¶
- Always, when demand is part of a scenario
- Network Optimization reads this table directly. The requested quantity becomes the demand it must satisfy, and the unit revenue becomes what it earns by satisfying it
Without it the optimizer has nothing to satisfy and no incentive to ship, and the run stops: a missing demand policy is one of its three refusals.
What you need¶
- An upstream Import Data node with one row per (location, product) you have demand for
- A column identifying the demand location, matching a location identifier
- A requested-quantity column on every row
- A per-unit revenue column. With Allow partial demand fulfillment on, every row needs a revenue, or the run stops
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 units, and every row is in it. Over MCP, set it in field_mappings as "quantity_unit": "__const__:units". Quantity Unit is required on every row with Requested Quantity or Unit Revenue, and the panel marks it required once one of those is mapped.
| Field | Type | Required | Example | What it is | Auto-detected headers |
|---|---|---|---|---|---|
| Location | text | Yes | Store 1 |
Where demand occurs. Must match a Location name. | location, loc, name, id, location_id, loc_id |
| Product | text | Yes | Widget |
Product or SKU demanded. Required — name it even in a single-product scenario. Must match a Product name. | product, sku, item, material, product_id |
| Requested Quantity | number | No | 100.0 |
Quantity requested at this location — the demand the optimizer tries to meet. Network Optimization refuses a row with no value. Must be greater than or equal to 0. Its unit goes in Quantity Unit. | requested_quantity, requested, quantity, qty, demand, demand_quantity |
| Quantity Unit | text | No | units |
Unit the requested quantity and the revenue per unit are in. Required on every row that carries one. A unit other than the scenario's needs a conversion for the product. | quantity_unit, qty_unit, unit, uom |
| Unit Revenue | number | No | 12.0 |
Revenue earned per unit fulfilled, in the scenario currency. Optimization requires a value on every row when it may leave demand unserved; when every order must be met it only scales the reported objective. Must be greater than or equal to 0. | unit_revenue, revenue, sales_price, price_per_unit |
How it works¶
Each row becomes a demand policy record. Network Optimization treats the requested quantity as the requirement at that (location, product) and the unit revenue as the reward for meeting it. With Allow partial demand fulfillment off on Network Optimization, which is the default, the requested quantity is a hard requirement.
Auto-detection maps a column called quantity to Requested Quantity. That is
usually right on the policy side: requested is what the optimizer must satisfy.
Workflow wiring¶
For an optimization, wire the policy side beside the other tables Network Optimization needs: locations, products, lanes and the supply policy.
flowchart LR
n1["Import Data (locations.csv)"] --> n2["Map Locations"]
n3["Import Data (products.csv)"] --> n4["Map Products"]
n5["Import Data (lanes.csv)"] --> n6["Map Lanes"]
n7["Import Data (supply.csv)"] --> n8["Map Supply Policy"]
n9["Import Data (demand.csv)"] --> n10["Map Demand Policy"]
n2 & n4 & n6 & n8 & n10 --> n11["Create Scenario"]
n11 --> n12["Network Optimization"]
n12 --> n13["Create Scenario (optimized)"]
For a baseline that also preserves observed fulfilment, fan the same file out to both:
flowchart LR
n1["Import Data (demand.csv)"] --> n2["Map Demand Policy"]
n1 --> n3["Map Demand State"]
n4["Import Data (locations.csv)"] --> n5["Map Locations"]
n6["Import Data (products.csv)"] --> n7["Map Products"]
n2 & n3 & n5 & n7 --> n8["Create Scenario"]
Common mistakes¶
- Mapping a total
revenuecolumn to Unit Revenue. It is per unit. A realized total belongs on Map Demand State as Realized Revenue. - Wiring only Map Demand State. The optimizer reads this table and never reads state. Without it there is no demand requirement and the run stops.
Messages this node can show¶
- Field matches several columns
- Mapped table empty
- Number outside its allowed bound
- Required field absent
- Row doesn’t fit its table
- Text padded with spaces
- Value not a plain number
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.