Refinery operations — feedstock scheduling and yield optimization
How refinery schedulers and commercial teams use NTHMAP to time feedstock deliveries and optimize refinery runs.
A refinery is a continuous chemical process that runs 24/7, with a shutdown/startup cycle that costs millions of dollars. Scheduling feedstock crude deliveries against refinery runs is a tight optimization problem: too much inbound crude creates expensive storage, too little creates expensive run cuts.
NTHMAP gives refinery commercial teams a live view of inbound feedstock — their own and their competitors'.
Your own inbound
You know what you've bought. You don't always know when it'll actually arrive. Captain-entered ETAs are notoriously unreliable. Weather delays and port congestion can shift delivery by days.
# Crude tankers inbound to your region with your preferred ETAs
nthmap vessels list \
--bbox -100,20,-80,32 \
--types "Crude Tanker" \
--min-load 80 \
--format json | \
jq '[.[] | {name, destination, eta, speed_knots, dwt, load_pct}]'
For each vessel currently sailing toward you, you can compute a realistic ETA based on current speed and distance to port (ignoring the possibly-stale captain-entered value).
Competitor inbound
Knowing what your competitors are receiving is an edge. If you're US Gulf Coast refinery and the other major Gulf refiners are receiving heavy light crude while you've just contracted medium sour, you're in a competitive disadvantage on product yields.
NTHMAP's draw tool gives you the competitive snapshot:
import nthmap
client = nthmap.Client(api_key="ntm_live_...")
# Your region's crude pipeline
result = client.draw_analyze(
geojson={"type": "Polygon", "coordinates": [[
[-100, 25], [-80, 25], [-80, 32], [-100, 32], [-100, 25]
]]},
draw_type="polygon"
)
print(f"US Gulf Coast crude inbound:")
print(f" Total tankers: {result['commodity_breakdown'].get('Crude Tanker', 0)}")
print(f" Estimated MT: {result['est_cargo_mt']:,.0f}")
print(f" Estimated barrels: {result['est_cargo_mt'] * 7:,.0f}")
Break down by flag to infer rough origin (Saudi flagged MH, Venezuelan etc).
Origin inference
NTHMAP doesn't tell you the cargo grade, but you can infer origin from last_port:
vessels = client.vessels(
bbox=[-100, 20, -80, 32],
types=["Crude Tanker"],
min_load=80,
)
by_origin = {}
for v in vessels:
origin = v.get("last_port_country", "Unknown")
by_origin.setdefault(origin, []).append(v)
for origin, vs in by_origin.items():
total_mt = sum(x["est_cargo_mt"] or 0 for x in vs)
print(f" {origin}: {len(vs)} tankers, {total_mt:,.0f} MT")
Output for a US Gulf snapshot:
Saudi Arabia: 12 tankers, 3,420,000 MT
Iraq: 8 tankers, 2,480,000 MT
Brazil: 5 tankers, 1,560,000 MT
Mexico: 4 tankers, 460,000 MT
Nigeria: 3 tankers, 920,000 MT
Colombia: 2 tankers, 380,000 MT
Saudi-origin crude is Arab Light or Arab Medium. Iraqi-origin is Basrah Light or Heavy. Brazilian is typically heavy sweet. This gives you a rough feedstock composition forecast for your region.
Refinery turnarounds
Major refinery turnarounds (scheduled maintenance) typically shut down 300-800 kbd of capacity for 30-60 days. NTHMAP tracks refineries as infrastructure but doesn't directly announce turnarounds — you need industry sources for that.
What NTHMAP can tell you: the inbound vessel signal. A refinery beginning turnaround stops accepting feedstock. Vessels destined for that refinery either divert or anchor. A refinery resuming normal operations ramps up its inbound vessel count.
# Check vessels near a specific refinery
nthmap vessels list --bbox $(bbox_around 29.866 -93.940 50)
Watch this number at 50km radius around Port Arthur refinery. When it drops below normal for several days, something is up.
Product tanker outbound
After refining, product (gasoline, diesel, jet fuel, naphtha) moves outbound on product tankers. Clean product tankers (also typed as "Chemical Tanker" or "Oil Products Tanker" in some registries) vs dirty crude tankers can be filtered:
nthmap vessels list \
--types "Chemical Tanker","Oil Products Tanker" \
--bbox -95,28,-90,30 \
--min-load 70
A refinery producing high product export means strong crack spreads — a signal for investors and competitors.
Integration example: refinery scheduling dashboard
REFINERIES = {
"Port Arthur": (29.866, -93.940, 635), # name, lat, lng, bpd in thousands
"Galveston Bay": (29.380, -94.940, 593),
"Baytown": (29.760, -95.020, 584),
"Garyville": (30.060, -90.620, 587),
}
for name, (lat, lng, capacity) in REFINERIES.items():
vessels = client.vessels(
bbox=[lng-0.5, lat-0.5, lng+0.5, lat+0.5],
types=["Crude Tanker"],
min_load=70,
)
inbound_mt = sum(v["est_cargo_mt"] or 0 for v in vessels)
inbound_bbl = inbound_mt * 7
days_feedstock = inbound_bbl / (capacity * 1000)
print(f"{name:20} | Capacity: {capacity*1000:>10,} bpd | Near: {len(vessels):3} tankers | ~{days_feedstock:.1f} days feedstock")
You've just built a live "days of crude in the pipeline" report for every major US Gulf Coast refinery.
Learn more
- Oil & gas trading — related crude trading workflow
- Port operations — port congestion affects feedstock delivery
- API reference — vessel and infrastructure endpoints