Economics of 2000 T Barge

1000-2000T Inland Barge Calculator :root { –navalt: #0A2540; –navalt-light: #1F4E78; –accent: #00B050; –negative: #C00000; –bg: #F7F9FC; –panel: #FFFFFF; –border: #E1E8F0; –text: #1A1A1A; –muted: #5A6678; } * { box-sizing: border-box; } .ibc-app { font-family: -apple-system, BlinkMacSystemFont, “Segoe UI”, Helvetica, Arial, sans-serif; background: var(–bg); color: var(–text); font-size: 14px; line-height: 1.5; margin: 0; padding: 0; min-height: 600px; } .ibc-header { background: var(–navalt); color: #fff; padding: 18px 28px; border-radius: 6px 6px 0 0; } .ibc-header h2 { margin: 0; font-size: 20px; font-weight: 600; } .ibc-header .sub { font-size: 12px; opacity: 0.85; margin-top: 3px; } .ibc-modetoggle { display: flex; gap: 8px; margin: 16px 28px 0; } .ibc-modetoggle button { flex: 1; padding: 10px; border: 1px solid var(–border); background: #fff; border-radius: 4px; cursor: pointer; font-weight: 600; font-size: 13px; color: var(–muted); } .ibc-modetoggle button.active { background: var(–navalt); color: #fff; border-color: var(–navalt); } .ibc-main { display: grid; grid-template-columns: 340px 1fr; gap: 20px; padding: 16px 28px 28px; } @media (max-width: 768px) { .ibc-main { grid-template-columns: 1fr; } } .ibc-panel { background: var(–panel); border: 1px solid var(–border); border-radius: 6px; padding: 18px; margin-bottom: 14px; } .ibc-panel h3 { margin: 0 0 10px; font-size: 13px; font-weight: 600; color: var(–navalt); text-transform: uppercase; letter-spacing: 0.5px; border-bottom: 2px solid var(–navalt-light); padding-bottom: 6px; } .ibc-panel h4 { margin: 10px 0 4px; font-size: 11px; font-weight: 600; color: var(–muted); text-transform: uppercase; letter-spacing: 0.3px; } .ibc-row { display: grid; grid-template-columns: 1fr 90px; gap: 8px; align-items: center; margin-bottom: 4px; } .ibc-row label { font-size: 12.5px; } .ibc-row input { width: 100%; padding: 4px 6px; border: 1px solid var(–border); border-radius: 3px; font-size: 12.5px; text-align: right; color: var(–navalt); font-weight: 600; background: #FAFBFD; } .ibc-row input:focus { outline: none; border-color: var(–navalt-light); background: #fff; } .ibc-advanced { display: none; } .ibc-advanced.show { display: block; } table { width: 100%; border-collapse: collapse; font-size: 12.5px; } th, td { padding: 5px 7px; text-align: right; border-bottom: 1px solid var(–border); } th:first-child, td:first-child { text-align: left; } th { font-weight: 600; color: var(–muted); font-size: 10.5px; text-transform: uppercase; letter-spacing: 0.3px; background: #F7F9FC; } tr.total td { font-weight: 700; background: #FFF8E0; border-top: 2px solid var(–navalt); } tr.subtotal td { font-weight: 600; background: #F0F4F9; } .ibc-num { font-variant-numeric: tabular-nums; } .ibc-good { color: var(–accent); font-weight: 600; } .ibc-bad { color: var(–negative); font-weight: 600; } .ibc-headlines { display: grid; grid-template-columns: repeat(4, 1fr); gap: 10px; margin-bottom: 14px; } @media (max-width: 600px) { .ibc-headlines { grid-template-columns: repeat(2, 1fr); } } .ibc-hl { background: var(–navalt); color: #fff; padding: 12px; border-radius: 5px; } .ibc-hl .lbl { font-size: 10.5px; opacity: 0.8; text-transform: uppercase; letter-spacing: 0.4px; } .ibc-hl .v { display: flex; justify-content: space-between; margin-top: 5px; font-variant-numeric: tabular-nums; } .ibc-hl .v div span { display: block; font-size: 9.5px; opacity: 0.65; } .ibc-hl .v div b { font-size: 16px; font-weight: 600; } .ibc-hl .v .ds { opacity: 0.7; } .ibc-hl .v .bs b { color: #7FE3A3; } .ibc-chart { max-width: 100%; height: 300px !important; } .ibc-note { font-size: 11px; color: var(–muted); font-style: italic; margin-top: 6px; } .ibc-reset { background: var(–navalt); color: #fff; border: none; padding: 7px 14px; border-radius: 3px; cursor: pointer; font-size: 12px; margin-top: 8px; width: 100%; } .ibc-tabs { display: flex; gap: 4px; margin-bottom: 12px; border-bottom: 2px solid var(–border); } .ibc-tabs button { background: none; border: none; padding: 8px 14px; cursor: pointer; font-weight: 600; color: var(–muted); border-bottom: 3px solid transparent; margin-bottom: -2px; font-size: 12.5px; } .ibc-tabs button.active { color: var(–navalt); border-bottom-color: var(–navalt); } .ibc-tabpane { display: none; } .ibc-tabpane.active { display: block; } .ibc-rotation-grid { display: grid; grid-template-columns: 70px repeat(6, 1fr); gap: 1px; background: var(–border); font-size: 10px; margin: 8px 0; } .ibc-rotation-grid div { background: #fff; padding: 4px; text-align: center; } .ibc-rotation-grid .hdr { background: var(–navalt); color: #fff; font-weight: 600; font-size: 9.5px; } .ibc-rotation-grid .lbl { background: #F0F4F9; font-weight: 600; text-align: left; padding-left: 6px; }

Inland Barge TCO Calculator

2000 T Diesel vs Battery Swap (LFP + Solar) — 28-Year Comparison

Inputs

Revenue & Operating

Cargo capacity (t)
Utilisation
Cargo rate (₹/t-km)

Energy Prices

Diesel price (₹/L)
Grid tariff (₹/kWh)

Financial

Discount rate
Energy escalation
Project horizon (yrs)

Vessel & Route

Voyage distance (km)
Swap stops
Operating days/yr
Fleet size (barges)

Power

BS power cruise (kW)
BS power manoeuv (kW)
Diesel scale factor
Diesel SFC (g/kWh)

CAPEX

Hull (Cr INR)
Diesel powertrain (Cr)
Electric powertrain (Cr)
Battery cost (₹/kWh)
Replacement (₹/kWh)

OPEX

Crew cost/day (₹)
Crew × shifts
Diesel maint %
BS maint %
Insurance %CAPEX

Battery

DoD
Degradation buffer
Pack ratio (:barges)
Replacement (yrs)

Other

Scrap % of hull
Solar plant (kW)
All formulas recalculate on every keystroke. Defaults match the published 2000 T model.

TCO Breakdown (PV, Cr INR)

Cumulative TCO (Nominal)

Voyage Profile

Battery Pack Sizing & Cycles

Pack Rotation (first 24 hrs)

Round-robin assignment, 4-hour fast charge at swap stations B/C/D.

Cargo Rate Sensitivity

Diesel Price Sensitivity

Lifecycle Emissions & Externalities

Net CO₂ savings = (diesel emissions) − (grid emissions). Improves substantially as the grid decarbonises.
https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.min.js (function() { const ids = [‘cargoCap’,’util’,’cargoRate’,’dieselPrice’,’gridRate’,’disc’,’energyEsc’,’horizon’, ‘dist’,’stops’,’opdays’,’fleet’,’pCruise’,’pManov’,’dieselScale’,’sfc’,’hull’,’dCapex’,’bsCapex’,’batCost’,’batReplCost’, ‘crewDay’,’crewSets’,’dMaint’,’bsMaint’,’insRate’,’dod’,’degr’,’packRatio’,’batCycle’,’scrap’,’solar’]; const defaults = {}; ids.forEach(id => defaults[id] = document.getElementById(id).value); window.ibcReset = function() { ids.forEach(id => document.getElementById(id).value = defaults[id]); recalc(); }; function getVals() { const v = {}; ids.forEach(id => v[id] = parseFloat(document.getElementById(id).value) || 0); return v; } function fmt(n, dec=1) { if (n === null || n === undefined || isNaN(n)) return ‘—’; if (Math.abs(n) >= 1000) return n.toLocaleString(‘en-IN’, {maximumFractionDigits:0}); return n.toFixed(dec); } function fmtPct(n) { return (n*100).toFixed(1) + ‘%’; } function npv(rate, flows) { let s = 0; for (let t = 0; t < flows.length; t++) s += flows[t] / Math.pow(1+rate, t+1); return s; } function irr(flows) { let lo=-0.99, hi=10; for (let i=0; i<100; i++) { const mid = (lo+hi)/2; let n = 0; for (let t=0; t<flows.length; t++) n += flows[t] / Math.pow(1+mid, t); if (Math.abs(n) 0) lo = mid; else hi = mid; } return (lo+hi)/2; } function payback(flows) { let cum = 0; for (let t=0; t= 0) return t; } return null; } function compute(v) { const H = Math.round(v.horizon); const tripDist = v.dist / (v.stops + 1); const tripsPerVoyage = v.stops + 1; const cruiseSpeed = 7; const manovSpeed = 5; const manovDist = 1; const tripTimeMin = (tripDist – manovDist)/cruiseSpeed/1.852*60 + manovDist/manovSpeed/1.852*60; const swapTime = 30, cargoTime = 1304; const voyageTimeMin = tripsPerVoyage*tripTimeMin + v.stops*swapTime + cargoTime; const voyageDays = voyageTimeMin / 1440; const noVoyages = Math.round(v.opdays / voyageDays); const cargoPerVoyage = v.cargoCap * v.util; const cargoPerYear = cargoPerVoyage * noVoyages; const revPerVoyage = cargoPerVoyage * v.dist * v.cargoRate; const revY1 = revPerVoyage * noVoyages / 1e7; const propEnergyPerLeg = v.pCruise * (tripTimeMin-6)/60 + v.pManov * 6/60; const propEnergyPerVoyage = propEnergyPerLeg * tripsPerVoyage; const auxLoad = 23; const auxEnergyPerVoyage = auxLoad * (tripsPerVoyage*tripTimeMin + v.stops*swapTime)/60; const auxCharging = auxLoad * cargoTime/60; const totalEnergyPerVoyage = propEnergyPerVoyage + auxEnergyPerVoyage + auxCharging; const solarPerVoyage = v.solar * 3.5 * voyageDays; const gridPerVoyage = totalEnergyPerVoyage – solarPerVoyage; const gridY1 = gridPerVoyage * v.gridRate * noVoyages / 1e7; const dieselPCruise = v.pCruise * v.dieselScale; const dieselPManov = v.pManov * v.dieselScale; const fuelPerHr = dieselPCruise * v.sfc / 850; const fuelManovPerHr = dieselPManov * 300 / 850; const fuelIdle = dieselPManov * v.sfc * 0.2 / 850; const fuelCargo = auxLoad * 300 / 850; const fuelPerTrip = fuelPerHr*(tripTimeMin-6)/60 + fuelManovPerHr*6/60 + fuelIdle*swapTime/60; const fuelPerLastTrip = fuelPerHr*(tripTimeMin-6)/60 + fuelManovPerHr*6/60 + fuelCargo*cargoTime/60; const fuelPerVoyage = fuelPerTrip * (tripsPerVoyage-1) + fuelPerLastTrip; const fuelPerYear = fuelPerVoyage * noVoyages; const dieselY1 = fuelPerYear * v.dieselPrice / 1e7; const propBatSize = propEnergyPerLeg * (1+v.degr) / v.dod; const auxBatSize = (auxLoad * tripTimeMin/60) * (1+v.degr) / v.dod; const batSize = propBatSize + auxBatSize; const onboardCapex = batSize * v.batCost / 1e7; const extraCapex = (v.packRatio – 1) * batSize * v.batCost / 1e7; const dieselCapex = v.hull + v.dCapex; const bsCapex = v.hull + v.bsCapex + onboardCapex + extraCapex; const crewY = v.crewDay * v.crewSets * v.opdays / 1e7; const dieselMaintY1 = dieselY1 * v.dMaint; const bsMaintY1 = gridY1 * v.bsMaint; const dieselIns = dieselCapex * v.insRate; const bsIns = bsCapex * v.insRate; const replCostPerEvent = batSize * v.packRatio * v.batReplCost / 1e7; function build(type) { const capex = type === ‘diesel’ ? dieselCapex : bsCapex; const energyY1 = type === ‘diesel’ ? dieselY1 : gridY1; const maintY1 = type === ‘diesel’ ? dieselMaintY1 : bsMaintY1; const ins = type === ‘diesel’ ? dieselIns : bsIns; const flows = [-capex]; const yearly = []; const cumNominal = [capex]; let c = capex; for (let y = 1; y <= H; y++) { const esc = Math.pow(1+v.energyEsc, y-1); const rev = revY1 * esc; const energy = energyY1 * esc; const maint = maintY1 * esc; const crew = crewY * esc; const insurance = ins; let batRepl = 0; if (type === 'bs' && y % v.batCycle === 0 && y npv(v.disc, arr); const revPV = pv(yearly.map(r => r.rev)); const energyPV = pv(yearly.map(r => r.energy)); const maintPV = pv(yearly.map(r => r.maint)); const crewPV = pv(yearly.map(r => r.crew)); const insPV = pv(yearly.map(r => r.insurance)); const batPV = pv(yearly.map(r => r.batRepl)); const scrapPV = pv(yearly.map(r => r.scrap)); const opex = energyPV + maintPV + crewPV + insPV + batPV; const tco = opex + capex – scrapPV; return { capex, revPV, energyPV, maintPV, crewPV, insPV, batPV, scrapPV, opex, tco, npv: revPV – tco, irr: irr(flows), payback: payback(flows), flows, yearly, cumNominal }; } return { v, tripTimeMin, tripDist, tripsPerVoyage, voyageDays, noVoyages, cargoPerYear, propEnergyPerVoyage, gridPerVoyage, fuelPerVoyage, fuelPerYear, propBatSize, auxBatSize, batSize, onboardCapex, extraCapex, revY1, gridY1, dieselY1, replCostPerEvent, diesel: build(‘diesel’), bs: build(‘bs’) }; } let chart; function recalc() { const v = getVals(); const r = compute(v); const d = r.diesel, b = r.bs; document.getElementById(‘ibc-headlines’).innerHTML = `
TCO (PV, Cr)
Diesel${fmt(d.tco)}
Battery Swap${fmt(b.tco)}
NPV (Cr)
Diesel${fmt(d.npv)}
Battery Swap${fmt(b.npv)}
IRR
Diesel${fmtPct(d.irr)}
Battery Swap${fmtPct(b.irr)}
Payback (yrs)
Diesel${d.payback ?? ‘—’}
Battery Swap${b.payback ?? ‘—’}
`; const row = (lbl, dv, bv, cls=”) => { const diff = dv – bv; const sign = diff > 0.01 ? ‘ibc-good’ : (diff < -0.01 ? 'ibc-bad' : ''); return `${lbl}${fmt(dv)}${fmt(bv)}${diff>=0?’+’:”}${fmt(diff)}`; }; document.getElementById(‘ibc-opex’).innerHTML = ` ComponentDieselBattery SwapSavings ${row(‘CAPEX’, d.capex, b.capex)} ${row(‘Energy (PV)’, d.energyPV, b.energyPV)} ${row(‘Maintenance (PV)’, d.maintPV, b.maintPV)} ${row(‘Crew (PV)’, d.crewPV, b.crewPV)} ${row(‘Insurance (PV)’, d.insPV, b.insPV)} ${row(‘Battery replacement (PV)’, d.batPV, b.batPV)} ${row(‘Scrap recovery (PV)’, -d.scrapPV, -b.scrapPV)} ${row(‘TCO’, d.tco, b.tco, ‘total’)} ${row(‘Revenue (PV)’, d.revPV, b.revPV, ‘subtotal’)} ${row(‘NPV’, d.npv, b.npv, ‘total’)} `; document.getElementById(‘ibc-voyage’).innerHTML = ` Voyage distance${fmt(v.dist)} km Number of stops${v.stops} Trip distance (each leg)${fmt(r.tripDist)} km Trips per one-way voyage${r.tripsPerVoyage} Trip running time${fmt(r.tripTimeMin/60,2)} hrs Voyage time (one-way)${fmt(r.voyageDays,2)} days Voyages per year${r.noVoyages} Cargo per voyage${fmt(v.cargoCap*v.util)} t Cargo per year${fmt(r.cargoPerYear)} t `; document.getElementById(‘ibc-battery’).innerHTML = ` Prop energy / voyage${fmt(r.propEnergyPerVoyage)} kWh Net grid energy / voyage${fmt(r.gridPerVoyage)} kWh Battery pack size${fmt(r.batSize)} kWh Onboard battery CAPEX₹${fmt(r.onboardCapex)} Cr Extra packs CAPEX (${v.packRatio.toFixed(1)}× ratio)₹${fmt(r.extraCapex)} Cr Replacement cost / event₹${fmt(r.replCostPerEvent)} Cr Replacement eventsYears ${Array.from({length: Math.floor((v.horizon-1)/v.batCycle)}, (_,i) => (i+1)*v.batCycle).join(‘, ‘)} `; let rotHtml = ‘
Hour
‘; for (let bb = 1; bb <= 6; bb++) rotHtml += `
Barge ${bb}
`; for (let h = 0; h < 24; h++) { rotHtml += `
${h.toString().padStart(2,’0′)}:00
`; for (let bb = 0; bb < 6; bb++) { const launch = bb * 4; if (h < launch) { rotHtml += '
‘; continue; } const hrFromLaunch = h – launch; const tt = r.tripTimeMin/60; const cycleHr = tt + 0.5; const legNum = Math.floor(hrFromLaunch / cycleHr); const inLeg = hrFromLaunch – legNum * cycleHr; if (legNum >= r.tripsPerVoyage) { rotHtml += ‘
cargo
‘; } else if (inLeg < tt) { rotHtml += `
B${((bb*r.tripsPerVoyage + legNum) % 9) + 1}
`; } else { rotHtml += ‘
swap
‘; } } } rotHtml += ‘
‘; document.getElementById(‘ibc-rotation’).innerHTML = rotHtml; const cargoRates = [1.06, 1.41, 1.75, 2.0, 2.25, 2.58, 3.0]; const cargoNotes = [‘IWT cost’,’Rail benchmark’,’Cost-plus’,’BASE’,’Stretch’,’Road benchmark’,’Premium’]; let sc = ‘Cargo rateDiesel NPVBS NPVGapNote‘; cargoRates.forEach((cr, i) => { const factor = cr / v.cargoRate; const dN = d.revPV * factor – d.tco; const bN = b.revPV * factor – b.tco; const isBase = Math.abs(cr – v.cargoRate) < 0.01; sc += `₹${cr.toFixed(2)}<td class="ibc-num ${dN${fmt(dN)}${fmt(bN)}+${fmt(bN-dN)}${cargoNotes[i]}`; }); sc += ‘‘; document.getElementById(‘ibc-sens-cargo’).innerHTML = sc; const dieselPrices = [80, 100, 120, 140]; const discRates = [0.05, 0.07, 0.09, 0.11]; let sd = ‘Diesel ₹/L‘; discRates.forEach(dr => sd += `${(dr*100).toFixed(0)}%`); sd += ‘‘; dieselPrices.forEach(dp => { sd += `₹${dp}`; discRates.forEach(dr => { const vTest = Object.assign({}, v, {dieselPrice: dp, disc: dr}); const rTest = compute(vTest); const dN = rTest.diesel.npv; sd += `<td class="ibc-num ${dN${fmt(dN)}`; }); sd += ‘‘; }); sd += ‘‘; document.getElementById(‘ibc-sens-diesel’).innerHTML = sd; const co2Diesel = r.fuelPerYear * 2.64 / 1000; const co2Grid = r.gridPerVoyage * r.noVoyages * 0.71 / 1000; const co2Grid2035 = r.gridPerVoyage * r.noVoyages * 0.35 / 1000; const netSaved = co2Diesel – co2Grid; const netSaved2035 = co2Diesel – co2Grid2035; document.getElementById(‘ibc-co2-table’).innerHTML = ` MetricPer yearLifetime (28y) Diesel fuel consumed (L)${fmt(r.fuelPerYear)}${fmt(r.fuelPerYear*28)} Diesel CO₂ (tonnes)${fmt(co2Diesel,0)}${fmt(co2Diesel*28,0)} BS grid CO₂ @ today (0.71 kg/kWh)${fmt(co2Grid,0)}${fmt(co2Grid*28,0)} Net CO₂ saved (today’s grid)${fmt(netSaved,0)}${fmt(netSaved*28,0)} BS grid CO₂ @ 2035 (0.35 kg/kWh)${fmt(co2Grid2035,0)}${fmt(co2Grid2035*28,0)} Net CO₂ saved (2035 grid)${fmt(netSaved2035,0)}${fmt(netSaved2035*28,0)} Diesel import substitution (₹ Cr)${fmt(r.fuelPerYear*v.dieselPrice/1e7)}${fmt(r.fuelPerYear*28*v.dieselPrice/1e7)} `; const labels = []; for (let y=0; y’₹’+v+’ Cr’ } } } } }); } ids.forEach(id => document.getElementById(id).addEventListener(‘input’, recalc)); document.getElementById(‘ibc-mode-lite’).addEventListener(‘click’, () => { document.getElementById(‘ibc-mode-lite’).classList.add(‘active’); document.getElementById(‘ibc-mode-full’).classList.remove(‘active’); document.getElementById(‘ibc-adv’).classList.remove(‘show’); }); document.getElementById(‘ibc-mode-full’).addEventListener(‘click’, () => { document.getElementById(‘ibc-mode-full’).classList.add(‘active’); document.getElementById(‘ibc-mode-lite’).classList.remove(‘active’); document.getElementById(‘ibc-adv’).classList.add(‘show’); }); document.querySelectorAll(‘.ibc-tabs button’).forEach(btn => { btn.addEventListener(‘click’, () => { document.querySelectorAll(‘.ibc-tabs button’).forEach(b => b.classList.remove(‘active’)); document.querySelectorAll(‘.ibc-tabpane’).forEach(p => p.classList.remove(‘active’)); btn.classList.add(‘active’); document.getElementById(btn.dataset.tab).classList.add(‘active’); }); }); recalc(); })();