Use this to calculate how much natural uranium and separative work you need to get
a given amount of enriched uranium at a certain enrichment, and so on. Learn more about [isotopes here]({% link isotopes.md %}).
Tails assay (wt %)
Feed assay (wt %)
Product Enrichment (wt %)
Choose Enrichment Preset
Natural Uranium (0.711%)
LEU (4%)
HALEU (20%)
Weapons-grade (90%)
LEU
Compute product mass from given feed mass
Compute feed mass from given product mass
Feed mass (kg or tonne)
Product mass (kg or tonne)
Tails mass (kg or tonne)
SWU (kg-SWU or tonne-SWU)
Copy current settings to clipboard
Cost of Feed U3O8 ($/kgU)
Cost of Conversion to UF6 ($/kgU)
Cost of SWU ($/kgSWU)
Fabrication cost ($/kgHM)
Average discharge burnup (MWd/kgHM)
Choose burnup preset
CANDU (7 MWd/kg)
Typical LWR (50 MWd/kg)
Deep burn open cycle (200 MWd/kg)
Multi-recycle breeder (800 MWd/kg)
Thermal efficiency (%)
Choose efficiency preset
Thermionic (6%)
Typical LWR (32%)
Sodium-cooled reactor (39%)
High-temperature gas-cooled reactor (43%)
Reload total (¢/kWh)
Reload SWU (¢/kWh)
Reload feed (¢/kWh)
Conversion (¢/kWh)
Fabrication (¢/kWh)
Required mined material (gU/MWh)
High-level waste (gHM/MWh)
Abbrevs:
- U - Uranium
- HM - Heavy Metal (e.g. Uranium, Neptunium, Pu, Cm, etc.)
- kWh - Kilowatt-hour electric
- MWh - Megawatt-hour electric
- MWd - Megawatt-day thermal
- SWU - Separative Work Unit
<script src='
https://cdn.plot.ly/plotly-2.16.1.min.js'></script>
<script>
let range=document.getElementById("enrich");
let number=document.getElementById('enrich-text')
let select=document.getElementById('enrich-select')
let tails_assay=document.getElementById('tails-assay')
let feed_assay=document.getElementById('feed-assay')
let feed_mass=document.getElementById('feed-mass')
let product_mass=document.getElementById('product-mass')
let tails_mass=document.getElementById('tails-mass')
let swu=document.getElementById('swu-mass')
let mode=document.getElementById('mode')
let prod_const=document.getElementById('productConstant')
let save=document.getElementById('save')
let burange=document.getElementById("burnup");
let bunumber=document.getElementById('burnup-text')
let buselect=document.getElementById('burnup-select')
let effrange=document.getElementById("eff");
let effnumber=document.getElementById('eff-text')
let effselect=document.getElementById('eff-select')
let powerrange=document.getElementById("power");
let powernumber=document.getElementById('power-text')
let powerselect=document.getElementById('power-select')
let feedcost=document.getElementById('feed-cost')
let swucost=document.getElementById('swu-cost')
let fabcost=document.getElementById('fab-cost')
let convcost=document.getElementById('conversion-cost')
let reload_total_cost=document.getElementById('reload-total-cost')
let reload_swu_cost=document.getElementById('reload-swu-cost')
let reload_feed_cost=document.getElementById('reload-feed-cost')
let reload_fab_cost=document.getElementById('reload-fab-cost')
let reload_conv_cost=document.getElementById('reload-conv-cost')
let reload_waste=document.getElementById('waste-per-kwh')
let reload_feed_mass=document.getElementById('reload-feed-mass')
tails_assay.addEventListener("input",(e)=>{
computeFeed();
})
feed_assay.addEventListener("input",(e)=>{
computeFeed();
})
product_mass.addEventListener("input",(e)=>{
computeFeed();
})
feed_mass.addEventListener("input",(e)=>{
computeFeed();
})
range.addEventListener("input",(e)=>{
let val = parseFloat(e.target.value);
if (val{
range.value=e.target.value;
select.value=""
setRange(e.target.value);
computeFeed();
})
select.addEventListener("change",(e)=>{
if (!e.target.value) {
return;
}
number.value=e.target.value;
range.value=e.target.value;
setRange(e.target.value);
computeFeed();
})
save.addEventListener("click", (e) => {
copySettingsToClipboard();
})
// burnup
burange.addEventListener("input",(e)=>{
let val = parseFloat(e.target.value);
bunumber.value=val;
buselect.value=""
computeCost();
})
bunumber.addEventListener("input",(e)=>{
burange.value=e.target.value;
buselect.value=""
computeCost();
})
buselect.addEventListener("change",(e)=>{
if (!e.target.value) {
return;
}
bunumber.value=e.target.value;
burange.value=e.target.value;
computeCost();
})
// efficiency
effrange.addEventListener("input",(e)=>{
let val = parseFloat(e.target.value);
effnumber.value=val;
effselect.value=""
computeCost();
})
effnumber.addEventListener("input",(e)=>{
effrange.value=e.target.value;
effselect.value=""
computeCost();
})
effselect.addEventListener("change",(e)=>{
if (!e.target.value) {
return;
}
effnumber.value=e.target.value;
effrange.value=e.target.value;
computeCost();
})
/*
// power
powerrange.addEventListener("input",(e)=>{
let val = parseFloat(e.target.value);
powernumber.value=val;
powerselect.value=""
})
powernumber.addEventListener("input",(e)=>{
powerrange.value=e.target.value;
powerselect.value=""
})
powerselect.addEventListener("change",(e)=>{
if (!e.target.value) {
return;
}
powernumber.value=e.target.value;
powerrange.value=e.target.value;
})
*/
function setRange(val) {
let label=document.getElementById("enrich-label");
if (val>=0.0 && val<0.7) {
label.innerHTML="Depleted";
}
else if (val==0.7) {
label.innerHTML="Natural";
}
else if (val>0.7 && val<=5) {
label.innerHTML="LEU";
}
else if (val>5 && val<=20.0) {
label.innerHTML="HALEU";
}
else if (val>20.0 && val<=99.0) {
label.innerHTML="HEU";
}
else if (val>99.0 && val<=100.0) {
label.innerHTML="😲";
}
else {
label.innerHTML="Impossible";
}
}
function computeFeed() {
// Compute feed and SWU given desired product and enrichment
// compute MF/MP = feed factor
let mode = document.querySelector('input[name="mode"]:checked').value
let feed_factor= get_feed_factor();
if (mode=="1") {
feed_mass.value = (feed_factor * product_mass.value).toFixed(3);
}
else {
product_mass.value = (feed_mass.value/feed_factor).toFixed(3);
}
let swu_factor=get_swu_factor(feed_factor)
swu.value = (swu_factor * product_mass.value).toFixed(3);
tails_mass.value = (feed_mass.value - product_mass.value).toFixed(3);
// update plot data
let u238 = {
x: ['Feed', 'Product', 'Tails'],
y: [feed_mass.value*(1-feed_assay.value/100.0),
product_mass.value*(1-number.value/100.0),
tails_mass.value*(1-tails_assay.value/100.0)
],
name: 'U238',
type: 'bar'
};
let u235 = {
x: ['Feed', 'Product', 'Tails'],
y: [feed_mass.value*(feed_assay.value/100.0),
product_mass.value*(number.value/100.0),
tails_mass.value*(tails_assay.value/100.0)
],
name: 'U235',
type: 'bar'
};
var data=[u238, u235];
Plotly.react('plot', data, layout);
computeCost();
}
function computeCost() {
// we want to know $SWU/kWh, $Feed/kWh, $Fab/kWh and total cost for plotting
// so we need SWU = SWUfactor*product * swu cost
// product = how much fuel is needed to make a kWh
// kg = 1 kWe * 1 hour * 1/eff [MWt/MWe] * 1/24 [day/hour] * 1/burnup [kg/(MWt*day)] * 1000 kW/MW)
let feed_factor = get_feed_factor();
let swu_factor = get_swu_factor(feed_factor)
let prod_kg_per_kwe = 100.0/(effnumber.value * 24.0 * burnup.value * 1000.0);
let swu_per_kwe = prod_kg_per_kwe * swu_factor;
let feed_per_kwe = prod_kg_per_kwe * feed_factor;
// convert to cents
let swu_cost_per_kwe = swu_per_kwe * swucost.value*100;
let feed_cost_per_kwe = feed_per_kwe * feedcost.value*100
let fab_cost_per_kwe = prod_kg_per_kwe*fabcost.value*100
let conv_cost_per_kwe = feed_per_kwe*convcost.value*100
let tcost = swu_cost_per_kwe + feed_cost_per_kwe + conv_cost_per_kwe + fab_cost_per_kwe;
reload_total_cost.value = tcost.toFixed(3);
reload_swu_cost.value = swu_cost_per_kwe.toFixed(3);
reload_feed_cost.value = feed_cost_per_kwe.toFixed(3);
reload_fab_cost.value = fab_cost_per_kwe.toFixed(3);
reload_conv_cost.value = conv_cost_per_kwe.toFixed(3);
reload_waste.value = (prod_kg_per_kwe*1000000).toFixed(3);
reload_feed_mass.value = (feed_per_kwe*1000000).toFixed(3);
}
function vx(x) {
// value function: gotta convert percentages to fraction
let xn = Number(x/100.0);
return (1.0-2*xn) * Math.log((1.0-xn)/xn);
}
function get_feed_factor(){
// feed factor = F/P
return (number.value - tails_assay.value)/(feed_assay.value-tails_assay.value);
}
function get_swu_factor(feed_factor) {
// swufactor= SWU/MP
let vxt = vx(tails_assay.value)
return (vx(number.value) - vxt) - feed_factor*(vx(feed_assay.value)-vxt);
}
function setInputVals() {
// These can all be passed in as query params
const input = new URLSearchParams(window.location.search);
tails_assay.value = input.get("tails-assay") || 0.25;
feed_assay.value = input.get("feed-assay") || 0.711;
number.value = input.get("enrich") || 4.0;
range.value = number.value;
setRange(number.value);
feed_mass.value = input.get("feed-mass") || 0;
product_mass.value = input.get("product-mass") || 1;
feed_mass.value = input.get("feed-mass") || 1;
if (input.get("mode") == "0") {
// check a checkbox
prod_const.checked=true
};
}
function copySettingsToClipboard() {
let params = new URLSearchParams([
["tails-assay", tails_assay.value],
["feed-assay", feed_assay.value],
["enrich", number.value],
["feed-mass", feed_mass.value],
["product-mass", product_mass.value],
["mode", prod_const.checked ? "0" : "1"],
]);
let text = new URL(`${location.protocol + '//' + location.host + location.pathname}?${params}`);
navigator.clipboard.writeText(text);
}
var trace1 = {
x: ['Feed', 'Product', 'Tails'],
y: [20, 14, 23],
name: 'U238',
type: 'bar'
};
var trace2 = {
x: ['Feed', 'Product', 'Tails'],
y: [12, 18, 29],
name: 'U235',
type: 'bar'
};
var data = [trace1, trace2];
var layout = {barmode: 'stack', yaxis: {
type: 'log', autorange: true,
},
autosize: true,
margin: {
t: 0
},
};
Plotly.newPlot('plot', data, layout);
window.onresize = function() {
Plotly.relayout('plot', {})
}
// compute initial values
setInputVals();
computeFeed();
</script>