MILP-based optimization of a mixed heavy-duty vehicle (HDV) fleet (BEV/ICE) over a single workday. The model assigns trips, schedules charging, and optionally leverages Vehicle-to-Grid (V2G) to minimize total operating costs. It uses Gurobi, generates synthetic trip and cost parameters, and supports scenario and year variations.
- Mixed fleet of BEV and ICE with configurable electrification share.
- End-to-end pipeline:
- Yearly and hourly cost parameter generation.
- Synthetic trip generation.
- MILP optimization (trip scheduling, vehicle assignment, SoC management, charging, V2G).
- Optional V2G with configurable usable battery window.
- Parallel scenario sweeps via multiprocessing.
- CSV results and optional SVG disposition plots.
- Configurable working hours and 30-minute time discretization.
- hdv_disposition_optimization.py — Main script (pipeline, optimization, export)
- modules/
- hdv_cost_parameter_generation.py — Generates yearly/hourly cost parameters
- hdv_trip_generation.py — Generates synthetic trips
- hdv_fleet_generation.py — Generates fleet and vehicle parameters
- data/ — Input/output folder for CSVs and plots (created/used by the script)
Note: The data/ CSVs are created/updated by the main script and its modules
- Python 3.10+ recommended
- Gurobi (with a valid license) and gurobipy
- OS-specific Gurobi libraries as required by your platform
- numpy
- pandas
- gurobipy
- matplotlib
- tqdm
- schedule
- Clone the repository
- git clone <REPO_URL>
- cd <REPO_NAME>
- Create a virtual environment (recommended)
- python -m venv .venv
- source .venv/bin/activate (Linux/macOS)
- .venv\Scripts\activate (Windows)
- Install dependencies
- pip install numpy pandas gurobipy matplotlib tqdm schedule
- Configure Gurobi
- Install Gurobi (see Gurobi docs)
- Activate license (e.g., grbgetkey ...)
- Test: python -c "import gurobipy as gp; print(gp.gurobi.version())"
By default, the script generates the trip dataset and energy cost parametrs automatically, runs a single case (10 vehicles, 50% BEV, 1 trip dataset, best-case scenario in 2025, V2G on), and saves outputs under data/
- python hdv_disposition_optimization.py
Generated files:
- data/hdv_cost_parameter_yearly_normalized.csv
- data/hdv_cost_parameter_hourly_normalized.csv
- data/hdv_trips_generated.csv
- data/hdv_potential_analysis_results_v=...csv
- Optional plot (if generate_outputs='on'):
- data/hdv_disposition_optimized_plot_.svg
Edit the top of hdv_disposition_optimization.py:
- Fleet composition:
- fleet_size_min, fleet_size_max, fleet_size_step
- fleet_electrification_min, fleet_electrification_max, fleet_electrification_step
- Trip datasets:
- start_dataset_id, end_dataset_id (subset of generated trips)
- Scenarios:
- scenario = ['best case'] or ['worst case']
- scenario_year = (supported: 2025–2045)
- V2G:
- v2g_status = ['on'] or ['off']
- v2g_allowed_battery_usage = 0.7 (e.g., 70% within an 85–15% SoC window)
- Workday window:
- day_start_time = '08:00'
- day_end_time = '18:00'
- Output generation:
- generate_outputs = 'off' | 'on' (plots, CSVs, prints; use only for single-scenario runs)
Parallelization:
- multiprocessing uses cpu_count() processes
- threads can be set via model.setParam('Threads', ...)
- if running multiple optimizations at once (e.g. multple fleet configurations or scenarios), deactivate the automatic energy price parameter generation (line 43) and trip datset generation (line 48) and run the corresponding modules manually once before the parallel-optimization
- Time discretization: 48 time steps (30-minute slots, 00:00–24:00).
- Decision variables:
- x_m_t_f: vehicle m drives trip f in time step t (binary).
- x_m_f: vehicle m is assigned to trip f (binary).
- x_m_t_l: vehicle m at location l (charging/parking) in time step t (binary).
- x_m_t_E: energy flow in time step t (continuous, ≥0).
- x_m_SoC: state of charge per vehicle and time step (continuous, ≥0).
- x_m_t_l_bev: BEV parked (for V2G) in time step t (binary).
- z_f_s: trip f starts at time s (binary).
- Key constraints:
- Exactly one start time per trip within the work window.
- Exactly one vehicle per trip.
- Mutual exclusivity per time step (driving vs. at a location).
- BEV SoC dynamics and capacity bounds; sufficient SoC at trip start.
- Post-trip charging windows for BEVs according to required charge steps.
- V2G only when a BEV is parked.
- Objective:
- Minimize operating costs (€/100km).
- Add per-slot charging overhead.
- Subtract V2G revenues (treated as negative costs) based on period revenue parameters and the allowed battery usage.
- Costs: €/100km (driving), €/MWh (V2G, aggregated over time periods)
- Energy: kWh (storage, consumption), with 30-minute steps
- Distances: km
- Time: 30-minute increments; work window defines feasible trip start times
- CSV with key metrics per run:
- iteration_number_[n]
- fleet_size_[n]
- scenario, year
- km_electrification_[%], fleet_electrification_[%]
- total_fleet_distance_[km], median_trip_distance_[km]
- v2g_revenue_total_[€]
- optimization_status, optimization_value_[€]
- v2g_status
- Optional SVG plot of per-vehicle activity (trip, charging, parking, V2G).
- For reproducible single-case analysis, set generate_outputs='on' and configure exactly one parameter point (no sweeps)
- For large sweeps, set MIPGap and/or TimeLimit to control runtime
- Adapt the fleet and trip generators in modules/ to your own data if needed
- Experiment with Gurobi parameters (Presolve, Aggregate, Cuts, Threads) for performance
- gurobipy import errors: verify Gurobi installation and license
- No plot produced: set generate_outputs='on' and run a single scenario point
- Memory pressure: reduce process count; note the periodic memory cleaning scheduled every 12h
- Infeasible models: check work window, trip durations, charging times, and electrification share/fleet size
Apache-2.0
If this work contributes to academic or industrial projects, please cite the repository with project and author details.
- Author: Tom Winkler, Institute of Automotive Technology, Technical University of Munich
- For questions, please open an issue in the repository
- v1.0.0: Initial public release with end-to-end pipeline, MILP core, V2G support, and multiprocessing