Skip to content

khb-git/downstream-refinery-lp

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Downstream Refinery LP

Linear programming optimization for petroleum refinery operations: optimal crude slate selection, unit utilization, and product blending to maximize gross refining margin under capacity, quality, and demand constraints.

This is the downstream complement to a broader oil & gas portfolio:

Why this project

Refinery LP is the canonical optimization problem in downstream oil & gas. Industrial tools like Aspen PIMS and Haverly's GRTMPS are LPs (often with non-linear extensions) at their core. Refineries use them to answer:

  • What crude slate should we buy this month?
  • Given product prices and operational constraints, what's the optimal product mix?
  • What's the shadow value of additional FCC capacity?

This project implements a simplified but faithful LP model that captures the essential structure: crudes with assay-driven yields, conversion units (FCC, reformer, hydrotreater), product blending with quality specs, and margin maximization.

Features

  • Crude assay handling: YAML-loaded assays for WTI, Brent, Arab Light, Maya — representative of light sweet through heavy sour crude grades
  • Process unit models: CDU, FCC, reformer, hydrotreater (and optional VDU)
  • Product blending: gasoline (with octane and RVP indices), diesel (with ULSD sulfur spec), jet fuel
  • LP formulation: PuLP-based model with CBC solver (no external solver required); typical solve time < 1 second
  • Three example refineries of increasing complexity:
    • Hydroskimming (CDU + HTU only)
    • Conversion (adds reformer)
    • Complex (full conversion: CDU + reformer + FCC + HTU)

Quick start

from refinery_lp.io.examples import complex_refinery
from refinery_lp.optimization.lp_model import RefineryLP

config = complex_refinery(cdu_capacity_bpd=100_000)
result = RefineryLP(config).solve()

print(f"Status: {result.status}")
print(f"Gross margin: ${result.objective_value:,.0f}/day")
print(f"\nOptimal crude slate:")
for crude, bpd in result.crude_purchases.items():
    if bpd > 1:
        print(f"  {crude:>6}: {bpd:>8,.0f} bpd")
print(f"\nProduct slate:")
for product, bpd in result.product_sales.items():
    if bpd > 1:
        print(f"  {product:>14}: {bpd:>8,.0f} bpd")

Installation

git clone https://github.com/khb-git/downstream-refinery-lp.git
cd downstream-refinery-lp
pip install -e ".[dev]"
pytest

Project structure

downstream-refinery-lp/
├── refinery_lp/
│   ├── crudes/
│   │   └── assay.py             # CrudeAssay + YAML loaders
│   ├── units/
│   │   └── units.py             # CDU, FCC, Reformer, Hydrotreater, VDU
│   ├── blending/
│   │   └── blending.py          # RVP indices, octane blending, product specs
│   ├── optimization/
│   │   └── lp_model.py          # The LP model
│   ├── viz/                     # (planned) Sankey diagrams, dashboards
│   └── io/
│       └── examples.py          # Pre-configured refinery scenarios
├── data/
│   └── assays/                  # Crude assay YAML files
├── tests/
├── notebooks/                   # Demo workflows
└── pyproject.toml

Methodology

LP formulation

Decision variables (all in barrels per day):

  • crude_buy[c]: barrels of crude c purchased
  • cut_to_fcc[c]: AGO from crude c sent to FCC
  • cut_to_reformer[c]: heavy naphtha from crude c sent to reformer
  • cut_to_htu[s]: streams sent to hydrotreater
  • <product>_blend[stream]: streams blended into final products
  • product_sale[p]: barrels of finished product p sold

Objective (maximize):

Revenue (product sales × prices)
  − crude purchase costs
  − variable opex (per-barrel processing costs)

Constraints:

  • Crude availability limits
  • Per-unit capacity constraints (CDU, FCC, reformer, hydrotreater)
  • Mass balance at every node: cut flows out ≤ assay yield × crude in
  • Product blend balance: barrels in = barrels of product sold
  • Quality specs: ULSD-style sulfur limit on diesel

Yield modeling

Each unit has a yield matrix mapping input streams to output streams. The CDU is unique — its yields come from crude-specific assays, so heavy crude produces more residue than light crude even on the same CDU. The FCC, reformer, and hydrotreater have crude-independent yields as a simplification (real refineries use crude-dependent yields).

Linearization choices

Several physically non-linear properties are linearized to keep the problem LP-tractable:

  • Octane blending: linear-by-volume (real practice uses interaction models like Ethyl RT-70; linear is an industry-standard simplification)
  • Sulfur blending: linear on volume basis (slight inaccuracy vs density-weighted)
  • RVP blending: uses Chevron blend index (RVP^1.25), which combines linearly on a volume basis

For more accurate quality blending, the next step beyond LP is an MILP or NLP with bilinear terms — the famous "pooling problem" in optimization literature.

Example results

For a 100,000 bpd complex refinery with typical mid-cycle prices (gasoline $95/bbl, diesel $100/bbl, heavy sour crude $58/bbl):

  • Optimal slate typically favors Maya (heavy sour) given the discount
  • Complex refinery margin ~$10-15/bbl crude processed
  • Hydroskimming margin substantially lower (often <$5/bbl) due to inability to upgrade residue and low-octane naphtha
  • FCC and reformer have positive shadow prices — they're capacity- limited and adding more would increase margin

Roadmap

  • Sankey diagram visualization of material flows
  • Pooling problem extension (bilinear quality blending)
  • Multi-period planning (inventory, contract obligations)
  • Demo notebook with sensitivity analysis
  • Streamlit dashboard for what-if analysis

References

  • Gary, J.H., Handwerk, G.E., & Kaiser, M.J. (2007). Petroleum Refining: Technology and Economics. CRC Press.
  • Maples, R.E. (2000). Petroleum Refinery Process Economics. PennWell.
  • Bechtel, B. (1981). "PIMS — Process Industry Modeling System."
  • Misener, R. & Floudas, C.A. (2009). "Advances for the Pooling Problem: Modeling, Global Optimization, and Computational Studies." Applied and Computational Mathematics 8(1).

License

MIT

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors