Split need for an item across multiple suppliers or activities
There are often cases where a factory sources from multiple suppliers, or even a factory decides to outsource some of it's demand for a product. To model this behavior, the Chaos Solver uses split nodes, or activity splits. In the example here, there are 2 splits:
Notice that there is limited inventory for flour at farm_a.
In an unconstrained scenario, farm_a would provide 0.2 * 80 = 16 units of flour, but it has just 10 units of flour.
The split node handles this scenario by reallocating the additional need to the other suppliers of flour, so instead of farms_b and farm_c providing 32 units of flour, they provide 35.
This logic allows all 80 units of flour to be provided to the bakery_shop and mimics how a real supply chain would respond to the constraint.
| bom_id | location | lead_time_days | activity_rank | activity_split |
|---|---|---|---|---|
| 1 | bakery_shop | 0.5 | 1 | 0.2 |
| bom_id | input_item | input_qty |
|---|---|---|
| 1 | flour | 4.00 |
| 1 | water | 1.00 |
| 1 | yeast | 0.05 |
| bom_id | output_item | output_qty |
|---|---|---|
| 1 | bread | 1 |
| location | item | need_date | demand_qty |
|---|---|---|---|
| bakery_shop | bread | 5/30/2026 | 100 |
| item | location | genesis | onhand_qty | notes |
|---|---|---|---|---|
| bread | bakery_shop | False | NaN | NaN |
| flour | bakery_shop | False | NaN | NaN |
| water | bakery_shop | True | NaN | assume unlimited supply |
| yeast | vendor_a | True | NaN | assume unlimited supply |
| bread | regional_bakery | True | NaN | NaN |
| flour | farm_a | False | 10.0 | NaN |
| flour | farm_b | True | NaN | NaN |
| flour | farm_c | True | NaN | NaN |
| item | from_location | to_location | lead_time_days | activity_rank | activity_split | note |
|---|---|---|---|---|---|---|
| flour | farm_a | bakery_shop | 2 | 1.0 | 0.2 | NaN |
| flour | farm_b | bakery_shop | 3 | 1.0 | 0.4 | NaN |
| flour | farm_c | bakery_shop | 3 | 1.0 | 0.4 | NaN |
| bread | regional_bakery | bakery_shop | 1 | 1.0 | 0.8 | this is split with a bom id |
| yeast | vendor_a | bakery_shop | 1 | NaN | NaN | add no rank or split, standard BodEdge should be added |
| demand_key | item | location | need_date | demand_qty | fulfilled_qty |
|---|---|---|---|---|---|
| 0 | bread | bakery_shop | 2026-05-30 | 100 | 100 |
| item | location | activity | activity_date | pegged_qty | demand_key |
|---|---|---|---|---|---|
| flour | farm_b | 0_item_genesis | 2026-05-26 12:00:00 | 35.0 | 0 |
| flour | farm_b | 7_shipment_from | 2026-05-26 12:00:00 | 35.0 | 0 |
| flour | farm_c | 0_item_genesis | 2026-05-26 12:00:00 | 35.0 | 0 |
| flour | farm_c | 7_shipment_from | 2026-05-26 12:00:00 | 35.0 | 0 |
| flour | farm_a | 5_BOH_usage | 2026-05-27 12:00:00 | 10.0 | 0 |
| flour | farm_a | 7_shipment_from | 2026-05-27 12:00:00 | 10.0 | 0 |
| yeast | vendor_a | 0_item_genesis | 2026-05-28 12:00:00 | 1.0 | 0 |
| yeast | vendor_a | 7_shipment_from | 2026-05-28 12:00:00 | 1.0 | 0 |
| bread | regional_bakery | 0_item_genesis | 2026-05-29 00:00:00 | 80.0 | 0 |
| bread | regional_bakery | 7_shipment_from | 2026-05-29 00:00:00 | 80.0 | 0 |
| water | bakery_shop | 0_item_genesis | 2026-05-29 12:00:00 | 20.0 | 0 |
| flour | bakery_shop | 2_shipment_to | 2026-05-29 12:00:00 | 35.0 | 0 |
| flour | bakery_shop | 2_shipment_to | 2026-05-29 12:00:00 | 35.0 | 0 |
| flour | bakery_shop | 2_shipment_to | 2026-05-29 12:00:00 | 10.0 | 0 |
| yeast | bakery_shop | 2_shipment_to | 2026-05-29 12:00:00 | 1.0 | 0 |
| flour | bakery_shop | 4_activity_split_output | 2026-05-29 12:00:00 | 80.0 | 0 |
| flour | bakery_shop | 6_BOM_input | 2026-05-29 12:00:00 | 80.0 | 0 |
| water | bakery_shop | 6_BOM_input | 2026-05-29 12:00:00 | 20.0 | 0 |
| yeast | bakery_shop | 6_BOM_input | 2026-05-29 12:00:00 | 1.0 | 0 |
| bread | bakery_shop | 2_shipment_to | 2026-05-30 00:00:00 | 80.0 | 0 |
| bread | bakery_shop | 3_BOM_output | 2026-05-30 00:00:00 | 20.0 | 0 |
| bread | bakery_shop | 4_activity_split_output | 2026-05-30 00:00:00 | 100.0 | 0 |
| level | from_location | to_location | item | ship_date | arrival_date | shipment_qty | demand_key |
|---|---|---|---|---|---|---|---|
| 2 | regional_bakery | bakery_shop | bread | 2026-05-29 00:00:00 | 2026-05-30 00:00:00 | 80.0 | 0 |
| 6 | vendor_a | bakery_shop | yeast | 2026-05-28 12:00:00 | 2026-05-29 12:00:00 | 1.0 | 0 |
| 12 | farm_a | bakery_shop | flour | 2026-05-27 12:00:00 | 2026-05-29 12:00:00 | 10.0 | 0 |
| 14 | farm_b | bakery_shop | flour | 2026-05-26 12:00:00 | 2026-05-29 12:00:00 | 35.0 | 0 |
| 16 | farm_c | bakery_shop | flour | 2026-05-26 12:00:00 | 2026-05-29 12:00:00 | 35.0 | 0 |
Loading Supply Chain Network from Files Running obo Solver ***Starting to plan for demand key 0*** At bakery_shop on 2026-05-30: Searching inventory for 100 units of bread At bakery_shop: No inventory for bread At bakery_shop: Searching rank 1.0 SplitOutputEdge Split-2 to bread-bakery_shop with LT 0.0 days --At bakery_shop: Searching bread-regional_bakery to Split-2 with LT 1.0 days for split 80/100 ----At regional_bakery on 2026-05-29: Genesis Node for bread. All 80 need satisfied --At bakery_shop: Found all expected split qty --At bakery_shop: Searching BOM-1 to Split-2 with LT 0.5 days for split 20/100 ----At BOM 1 input 1/3: Searching for 80 of flour ------At bakery_shop on 2026-05-29: Searching inventory for 80 units of flour ------At bakery_shop: No inventory for flour ------At bakery_shop: Searching rank 1.0 SplitOutputEdge Split-1 to flour-bakery_shop with LT 0.0 days --------At bakery_shop: Searching flour-farm_a to Split-1 with LT 2.0 days for split 16/80 ----------At farm_a on 2026-05-27: Searching inventory for 16 units of flour ----------At farm_a: Found 10/16 inventory for flour ----------At farm_a: No parent edges to search. Returning found supply 10.0 --------At bakery_shop: Found ratio 0.125 is less than expected 0.2 --------At bakery_shop: Continuing to plan with adjuseted splits: ['0.1250', '0.4375', '0.4375']. --------At bakery_shop: Searching flour-farm_b to Split-1 with LT 3.0 days for split 35/80 ----------At farm_b on 2026-05-26: Genesis Node for flour. All 35 need satisfied --------At bakery_shop: Found all expected split qty --------At bakery_shop: Searching flour-farm_c to Split-1 with LT 3.0 days for split 35/80 ----------At farm_c on 2026-05-26: Genesis Node for flour. All 35 need satisfied --------At bakery_shop: Found all expected split qty --------At bakery_shop: Found all qty for Split-1 ------At bakery_shop: Found 80/80 on edge Split-1 to flour-bakery_shop ------At bakery_shop: Found all supply. Done searching edges of flour-bakery_shop ----At BOM 1 input 1/3: Found all supply for flour ----At BOM 1 input 2/3: Searching for 20 of water ------At bakery_shop on 2026-05-29: Genesis Node for water. All 20 need satisfied ----At BOM 1 input 2/3: Found all supply for water ----At BOM 1 input 3/3: Searching for 1 of yeast ------At bakery_shop on 2026-05-29: Searching inventory for 1 units of yeast ------At bakery_shop: No inventory for yeast ------At bakery_shop: Searching BodEdge yeast-vendor_a to yeast-bakery_shop with LT 1.0 days --------At vendor_a on 2026-05-28: Genesis Node for yeast. All 1 need satisfied ------At bakery_shop: Found 1/1 on edge yeast-vendor_a to yeast-bakery_shop ------At bakery_shop: Found all supply. Done searching edges of yeast-bakery_shop ----At BOM 1 input 3/3: Found all supply for yeast ----At BOM 1: Done searching all inputs --At bakery_shop: Found all expected split qty --At bakery_shop: Found all qty for Split-2 At bakery_shop: Found 100/100 on edge Split-2 to bread-bakery_shop At bakery_shop: Found all supply. Done searching edges of bread-bakery_shop ***Found 100.00% supply for demand key 0*** Solver complete. Writing output to .\tests\activity_split\out_obo
Created by Bill Ulrich
See the About page for more details