SAP recently introduced much awaited Transportation Load Building (TLB) functionality in SAP IBP. TLB helps planners to group planned distribution receipts into optimized transportation loads to utilize transportation equipment in the best possible way.
The objective of this blog is to explain how TLB optimization generally works and the mathematical modeling behind it. We will look at a very simplified example to demonstrate how load requisitions can be generated.
If you’re interested to know how to setup TLB in SAP IBP, refer this link.
How TLB works?
In a 2-step process, first determine the mix of transportation equipment required and then calculate number of products to be loaded on each of these transportation equipment.
Consider 2 finished goods LPFGIBP02 and LPFGIBP04 being transported from 4101 to 4301. There are 3 equipment available for transportation viz., Large Truck, Medium Truck and Small Truck. Following constraints are modeled using master data.
Master Data Setup
Fixed Cost of Equipment Type modeled in Transportation Group Equipment MDT.
Fixed cost is used to optimally determine mix of equipment type.
Equipment Type Constraints in Equipment Type Limit MDT.
Material Constraints like dimension, weight etc., in Alternate Unit of Measure MDT.
Referring above conversion w.r.t. base UoM can be calculated as :
M3 | PAL | TON | |
LPFGIBP02 | 0.5 | 0.25 | 0.001 |
LPFGIBP04 | 0.333333 | 0.142857 | 0.000125 |
Finally, assigning the transportation group to t-lane in Transportation Lanes MDT.
Note that, here additional constraints in form of minimum, rounding lot size etc., can be modeled. Here, it is left blank.
TLB Optimization
There are 2 steps of optimization.
1. To determine mix of equipment types
Here, we make use of fixed costs to determine lowest cost to be incurred considering optimal mix of equipment types.
We have 2 planned distribution receipts. 900 units of LPFGIBP02 and 1111 units of LPFGIBP04.
Consider x11, x12 and x13 be variables to denote number of large trucks, medium trucks and small trucks required respectively.
Objective function
Minimize z : 800*x11 + 250*x12 + 140*x13
Subject to constraints
x11,x12,x13 >= 0 and integers
600*x11 + 400*x12 + 200*x13 >= 900*0.5 + 1111*0.333333 (Volume/M3 constraint)
300*x11 + 200*x12 + 100*x13 >= 900*0.25 + 1111*0.142857 (PAL constraint)
100*x11 + 50*x12 + 25*x13 >= 900*0.001 + 1111*0.000125 (TON constraint)
You can use any analytical tool or MS Excel solver to determine x11,x12 and x13. Below is the sample code in Python.
!pip install PulP
from pulp import LpMinimize, LpProblem, LpStatus, lpSum, LpVariable
# Create the model
model = LpProblem(name="mix_equipment_type", sense=LpMinimize)
# Initialize the decision variables
x11 = LpVariable(name="x11", lowBound=0, cat="Integer")
x12 = LpVariable(name="x12", lowBound=0, cat="Integer")
x13 = LpVariable(name="x13", lowBound=0, cat="Integer")
# Add the constraints to the model
model += (600*x11 + 400*x12 + 200*x13 >= 900*0.5 + 1111*0.333333, "C1")
model += (300*x11 + 200*x12 + 100*x13 >= 900*0.25 + 1111*0.142857, "C2")
model += (100*x11 + 50*x12 + 25*x13 >= 900*0.001 + 1111*0.000125, "C3")
# Add the objective function to the model
model += 800*x11 + 250*x12 + 140*x13
status = model.solve()
print(f"status: {model.status}, {LpStatus[model.status]}")
for var in model.variables():
print(f"{var.name}: {var.value()}")
With above constraints, optimal values are
x11 = 0, x12 = 2, x13 = 1
This means we would need 0 Large Truck, 2 Medium Trucks and 1 Small Truck
2. Determine load requisition of each product on each equipment type
Consider x11, x12, x13 be variables to denote units of LPFGIBP02 to be loaded on Medium Truck 1, Small Truck and Medium Truck 2 respectively. Similarly, consider x21,x22,x23 be variables to denote units of LPFGIBP04 to be loaded on Medium Truck 1, Small Truck and Medium Truck 2 respectively.
The objective here is to distribute total receipts of both products 2011 (900+1111) in given mix of equipment type Large Truck = 0, Medium Truck = 2, Small Truck = 1
Objective function
Minimize z : x11 + x12 + x13 + x21 + x22 + x23 – 2011
Subject to constraints
x11,x12,x13,x21,x22,x23 >= 0
0.5*x11 + 0.333333*x21 <= 400 (M3 upper threshold of Medium Truck 1)
0.5*x12 + 0.333333*x22 <= 200 (M3 upper threshold of Small Truck)
0.5*x13 + 0.333333*x23 <= 400 (M3 upper threshold of Medium Truck 2)
0.25*x11 + 0.142857*x21 <= 200 (PAL upper threshold of Medium Truck 1)
0.25*x12 + 0.142857*x22 <= 100 (PAL upper threshold of Small Truck)
0.25*x13 + 0.142857*x23 <= 200 (PAL upper threshold of Medium Truck 2)
0.001*x11 + 0.000125*x21 <= 50 (TON upper threshold of Medium Truck 1)
0.001*x12 + 0.000125*x22 <= 25 (TON upper threshold of Small Truck)
0.001*x13 + 0.000125*x23 <= 50 (TON upper threshold of Medium Truck 2)
x11 + x12 + x13 + x21 + x22 + x23 – 2011 = 0 (Overall units of both products to be loaded)
x11 + x12 + x13 = 900 (Total units of LPFGIBP02 to be loaded)
x21 + x22 + x23 = 1111 (Total units of LPFGIBP04 to be loaded)
Below is the sample code in Python.
!pip install PulP
from pulp import LpMinimize, LpProblem, LpStatus, lpSum, LpVariable
# Import GLPK solver
!apt-get install -y -qq glpk-utils
import pulp as pl
solver = pl.GLPK_CMD()
# Create the model
model = LpProblem(name="load_receipts", sense=LpMinimize)
# Initialize the decision variables
x11 = LpVariable(name="x11", lowBound=0, cat='Continuous')
x12 = LpVariable(name="x12", lowBound=0, cat='Continuous')
x13 = LpVariable(name="x13", lowBound=0, cat='Continuous')
x21 = LpVariable(name="x21", lowBound=0, cat='Continuous')
x22 = LpVariable(name="x22", lowBound=0, cat='Continuous')
x23 = LpVariable(name="x23", lowBound=0, cat='Continuous')
# Add the constraints to the model
model += (0.5*x11 + 0.333333*x21 <= 400)
model += (0.5*x12 + 0.333333*x22 <= 200)
model += (0.5*x13 + 0.333333*x23 <= 400)
model += (0.25*x11 + 0.142857*x21 <= 200)
model += (0.25*x12 + 0.142857*x22 <= 100)
model += (0.25*x13 + 0.142857*x23 <= 200)
model += (0.001*x11 + 0.000125*x21 <= 50)
model += (0.001*x12 + 0.000125*x22 <= 25)
model += (0.001*x13 + 0.000125*x23 <= 50)
model += (x11 + x12 + x13 + x21 + x22 + x23 - 2011 == 0)
model += (x11 + x12 + x13 == 900)
model += (x21 + x22 + x23 == 1111)
# Add the objective function to the model
model += x11 + x12 + x13 + x21 + x22 + x23-2011
status = model.solve(solver)
print(f"status: {model.status}, {LpStatus[model.status]}")
for var in model.variables():
print(f"{var.name}: {var.value()}")
With above constraints, optimal values are
x11 = 59.3341, x12 = 40.6659, x13 = 800, x21 = 1111, x22 = 0, x23 = 0
Summary Table
LPFGIBP02 | LPFGIBP04 | |
Medium Truck 1 | 59.3341 | 1111 |
Small Truck | 40.6659 | 0 |
Medium Truck 2 | 800 | 0 |
Total | 900 | 1111 |
In SAP IBP, planners can simply run a standard application job template – Order-Based Planning: Transportation Load Building Run to generate load receipts.
With the given set of master data and distribution receipts, SAP IBP generates below load receipts which can be visualized in planner workspace.
The complexity of mathematical model goes up with the increase in number of constraints. Note that, there could be one or more feasible solutions depending on constraints that are modeled. The output may also differ depending on solvers being used. SAP might be using different set of solvers or methodology to derive the same outcome. However, this information is not available publicly. Note that, the algorithm of TLB optimization explained over here is based on generic understanding of TLB and not the exact algorithm offered by SAP.
I hope this blog was helpful to understand working principle of Transport Load Building (TLB) optimization.
The views, thoughts and opinions expressed in the blog belong solely to the author, and not to the author’s employer, any organization, committee, or other group or individual.