I am working on an optimisation problem that involves minimising shipping demurrage. I am struggling to model how to represent the difference, (x-y) between dates where the ship is ready to be loaded and when the ship is actually loaded. This difference, in days, is where demurrage charges are incurred (if applicable).
How can I calculate this difference in pulp and model the 'vessel_ready_to_load' date vs the 'vessel_start_load' date?
Code below:
planning_horizon_dates ['2020-01-01', '2020-01-02', '2020-01-03']
# Port inventory
port_stock_inventory = {
'RBL': {'current': 200000,
'target': 180000, # Note targets are set by separate opt.
'max': 200000},
'RB2': {'current': 200000,
'target': 180000,
'max': 200000},
'PRE': {'current': 200000,
'target': 180000,
'max': 200000},
'AFL': {'current': 200000,
'target': 180000,
'max': 200000},
'ACA': {'current': 200000,
'target': 180000,
'max': 200000}}
sales_demand_by_vessel ={
'2020-01-01': {
'CEYLON': {
'MAF': 0, 'PRE': 40000, 'ZBL': 0, 'AFE': 10000, 'AAC': 70000
},
'KONOS': {
'MAF': 0, 'PRE': 100000, 'ZBL': 0, 'AFE': 0, 'AAC': 0
},
'BULK JAPAN': {
'MAF': 30000, 'PRE': 0, 'ZBL': 70000, 'AFE': 0, 'AAC': 0
},
'XIN FA HAI': {
'MAF': 0, 'PRE': 0, 'ZBL': 9000, 'AFE': 20000, 'AAC': 0
}
},
'2020-01-02': {
'PACIFIC MAJOR': {
'MAF': 50000, 'PRE': 0, 'ZBL': 60000, 'AFE': 10000, 'AAC': 0
},
'CCSC YASA JING': {
'MAF': 10000, 'PRE': 0, 'ZBL': 0, 'AFE': 0, 'AAC': 60000
},
'XIAOMING HAO HAI': {
'MAF': 30000, 'PRE': 0, 'ZBL': 70000, 'AFE': 0, 'AAC': 0
},
'ROBUSTA': {
'MAF': 0, 'PRE': 0, 'ZBL': 0, 'AFE': 50000, 'AAC': 0
}
},
'2020-01-03': {
'AQUA': {
'MAF': 0, 'PRE': 0, 'ZBL': 0, 'AFE': 10000, 'AAC': 70000
},
'ARUN': {
'MAF': 0, 'PRE': 0, 'ZBL': 50000, 'AFE': 0, 'AAC': 0
},
'HARALL': {
'MAF': 30000, 'PRE': 0, 'ZBL': 70000, 'AFE': 0, 'AAC': 0
},
'MAMBO': {
'MAF': 0, 'PRE': 0, 'ZBL': 9000, 'AFE': 20000, 'AAC': 0
}
},
}
# DECISION VARIABLES
# Binary indicators for all possible vessel load dates after NOR date.
vessel_load_start_date = pulp.LpVariable.dicts(
'Vessel Load Start Date',
((vessel, date) for vessel, date in load_start_dates.index),
lowBound=0,
cat='Binary')
# Vessel Sales Demand
vessel_sales_demand_vars = pulp.LpVariable.dicts(
'Vessel Sales Complete',
((vessel, product, date) for product in products for vessel, date in load_start_dates.index),
lowBound=0,
cat='Continuous'
)
# Vessel grade requirements
vessel_product_requirements = pulp.LpVariable.dicts(
"Vessel-Grade Requirement Tonnes",
((vessel, product) for vessel in vessels for product in products),
lowBound=0,
cat='Continuous')
# Model
model = pulp.LpProblem('Demurrage Optimisation', pulp.LpMinimize)
# Objective Function
model += pulp.lpSum([
demurrage_charge_vars[vessel]
for vessel in demurrage_charge_vars])
# Vessel can ONLY begin loading if there is sufficient supply of each product
for vessel in vessels:
model += port_inventory[date][product] >= sales_demand_by_vessel[date][vessel][product] ==
load_start_date[vessel]
# Vessel loading can only on or after notification of readiness
for vessel in vessels:
model += load_start_date[vessel] >= readiness_date_dict[vessel]
model += load_start_date_dict[vessel] - readiness_date_dict[vessel] * daily_dem_rate == demurrage_charge_vars[date][vessel]
# Control vessel loading
for product in products:
for vessel, date in vessel_load_start_date:
vessel_sales_demand_vars[(vessel, product, date)] - vessel_product_requirements[vessel, product] * load_start_date[vessel, date] <= 0
Any help very gratefully received!