Map Inventory State
Map raw rows into the scenario's inventory state table: the observed inventory at each location, the average level over the horizon, and the carrying cost realized.
This is the output side of inventory. Pair it with Map Inventory Policy for the per-unit rate.
When to use this¶
- Inventory is part of the scenario and you have observed levels or carrying-cost totals
- Cost to Serve reads the realized carrying cost when attributing inventory cost to customers
Network Optimization does not read this table. It writes it fresh every run, for each inventory policy row with days of inventory, from that policy and the solved throughput: the realized carrying cost, and the average inventory when Create Scenario states a Horizon Start and Horizon End. A scenario optimized with no inventory policy comes back with no inventory state, even when you mapped one here.
What you need¶
- An upstream Import Data node with one row per (location, product) you have observations for
- An average-inventory column or a realized-carrying-cost column, typically both
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 Inventory 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 "inventory_unit": "__const__:units". Inventory Unit is required on every row with Average Inventory, and the panel marks it required once it is mapped.
| Field | Type | Required | Example | What it is | Auto-detected headers |
|---|---|---|---|---|---|
| Location | text | Yes | Warehouse A |
Where inventory was held. Must match a Location name. | location, loc, name, id, location_id, loc_id |
| Product | text | Yes | Widget |
Product or SKU. Required — name it even in a single-product scenario. Must match a Product name. | product, sku, item, material, product_id |
| Average Inventory | number | No | 350.0 |
Average inventory level actually held in the recorded baseline. A level rather than a flow, so it does not compare with a quantity moved over the period, and a total over sites and products is a total of averages, not an average. Must be greater than or equal to 0. Its unit goes in Inventory Unit. | average_inventory, avg_inventory, inventory, stock, avg_stock |
| Inventory Unit | text | No | units |
Unit the average inventory is in. Required on every row that carries one. A unit other than the scenario's needs a conversion for the product. | inventory_unit, stock_unit, unit |
| Realized Carrying Cost | number | No | 35.0 |
Total carrying cost actually incurred in the baseline (not per-unit) — what holding that stock costs over the horizon, capital, storage and risk together. Negative amounts record credits against this cost. | realized_carrying_cost, carrying_cost, inventory_carrying_cost, holding_cost, storage_cost |
How it works¶
Each row becomes an inventory state record. Average inventory and realized carrying cost are separate concepts. The first is a quantity in your inventory unit; the second is money in the scenario currency. Create Scenario holds the inventory unit to the scenario's Unit as it does every other quantity: a row with an average inventory and no unit is refused, and so is a unit with no conversion to the scenario's unit for the row's product. Cost to Serve reads the second when rolling up cost per customer.
Workflow wiring¶
flowchart LR
n1["Import Data (inventory.csv)"] --> n2["Map Inventory Policy"]
n1 --> n3["Map Inventory 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 the per-unit rate here. It belongs on Map Inventory Policy.
- Confusing Average Inventory with Realized Carrying Cost. Different units, different meanings. One is a quantity, the other is money.
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.