Works out the CO2-equivalent emissions of vented and burned streams, fired heaters and electric units, per second and per year.
How the precision is kept
The arithmetic is 64-bit sums and products. The factors set the accuracy: published fuel factors typed to two decimals, 100-year warming potentials as whole numbers, formation enthalpies to six digits, a CO2 molar mass of 0.04401 kg/mol and a million-Btu constant written to seven digits. An electricity factor is never assumed: a unit without one is reported as a problem and left out of the total.
Calculations under this policy
4 calculations in 1 source file. The code is read from the released app when this page loads. It is the calculation people run, not a copy kept for this page.
The three formation enthalpies are written as whole joules per mole (-393509, -241818, -285830), so the result carries the six digits of that table. A negative result is set to 0.
process/emissions.js
lines 17 to 25
CadCraft 0.8.2
/** Heating values J/mol of a combustible component (C/H/O/N only) from the formation enthalpies: lower (water as gas) and higher (liquid). */
export function heatingValue(th, id) {
const i = th.index(id), c = th.c[i], a = atoms(c.formula), co2 = th.c[th.index('co2')] || null;
const hco2 = -393509, hh2og = -241818, hh2ol = -285830;
for (const k of Object.keys(a)) if (!['C', 'H', 'O', 'N'].includes(k)) return null;
const nC = a.C || 0, nH = a.H || 0, hf = c.hf || 0;
const lhv = hf - nC * hco2 - (nH / 2) * hh2og, hhv = hf - nC * hco2 - (nH / 2) * hh2ol;
return { lhv: Math.max(lhv, 0), hhv: Math.max(hhv, 0), source: 'SVN7 Table C.4 formation enthalpies' };
}
Complete combustion of a stream
64-bit
The CO2 and water produced, the oxygen needed and the heat released when a stream is burned.
CO2 = Σ nᵢ × Cᵢ; H2O = Σ nᵢ × Hᵢ ÷ 2; O2 = Σ nᵢ × (Cᵢ + Hᵢ ÷ 4 − Oᵢ ÷ 2); kg CO2 = CO2 × 0.04401
Mole flows are summed over the components in order, in 64-bit. The mass of CO2 uses a molar mass of 0.04401 kg/mol, four significant digits. CO2 already in the stream is counted; a component whose lower heating value is not above zero is skipped.
process/emissions.js
lines 26 to 37
CadCraft 0.8.2
/** Complete combustion of a stream: CO2 and water produced (mol/s, kg/s), the heat released (W, LHV and HHV) and the oxygen needed. */
export function combustion(th, s) {
let co2 = 0, h2o = 0, o2 = 0, lhv = 0, hhv = 0;
for (let i = 0; i < th.n; i++) {
const n = s.F * s.z[i], a = atoms(th.c[i].formula), id = th.ids[i];
if (id === 'co2' || id === 'water') { if (id === 'co2') co2 += n; continue; }
const v = heatingValue(th, id); if (!v) continue; const burns = (a.C || 0) + (a.H || 0) > 0 && v.lhv > 0;
if (!burns) continue;
co2 += n * (a.C || 0); h2o += n * (a.H || 0) / 2; o2 += n * ((a.C || 0) + (a.H || 0) / 4 - (a.O || 0) / 2); lhv += n * v.lhv; hhv += n * v.hhv;
}
return { co2, h2o, o2, co2kg: co2 * 0.04401, lhv, hhv };
}
Vented stream as CO2 equivalent
64-bit
The CO2-equivalent mass flow of a stream released to the air.
CO2e = Σ F × zᵢ × MWᵢ × GWPᵢ
One 64-bit sum of products. The warming potentials are whole numbers, CO2 1 and methane 28; every other component adds nothing.
process/emissions.js
lines 38 to 43
CadCraft 0.8.2
/** Direct release of a stream: kg CO2e/s using the GWP table (components without an entry count 0). */
export function vent(th, s) {
let kg = 0; const parts = {};
for (let i = 0; i < th.n; i++) { const g = GWP_AR5[th.ids[i]]; if (!g) continue; const m = s.F * s.z[i] * th.c[i].MWkg; parts[th.ids[i]] = m; kg += m * g; }
return { co2e: kg, parts, gwp: GWP_SOURCE };
}
Emissions report
64-bit
The emission of each tagged stream, fired unit and electric unit, the total per second and the total per year.
fired: CO2e = |Q| ÷ efficiency ÷ 1.055056e9 × factor; electric: CO2e = (|W| + |Q|) ÷ 3.6e6 × grid factor; per year = total × 3600 × hours
The joules in a million Btu are written 1.055056e9, a seven-digit constant; 3.6e6 J per kWh is exact. The fuel factors have two decimals (natural gas 53.06 kg CO2 per million Btu). An efficiency that is missing or zero is replaced by 0.85.
process/emissions.js
lines 44 to 63
CadCraft 0.8.2
/** The report. tags: { streamId: 'vent' | 'combust' }, fired: { unitId: { fuel: key of FUEL_CO2_PER_MMBTU, efficiency } }, electric: { unitId: { kgCO2ePerKWh } }
* (the person's factor), hours (default 8000/year). All results kg CO2e per second and per year. */
export function emissionsReport(th, res, { tags = {}, fired = {}, electric = {}, hours = 8000 } = {}) {
const rows = [], problems = []; let total = 0;
for (const [id, kind] of Object.entries(tags)) {
const s = res.streams[id]; if (!s) continue;
const r = kind === 'combust' ? combustion(th, s) : null, co2e = kind === 'combust' ? r.co2kg : vent(th, s).co2e;
rows.push({ kind: kind === 'combust' ? 'stream burned' : 'stream vented', id, co2e }); total += co2e;
}
for (const [id, f] of Object.entries(fired)) {
const q = Math.abs((res.units[id] || {}).Q || 0), fac = FUEL_CO2_PER_MMBTU[f.fuel]; if (fac == null) { problems.push(`unknown fuel ${f.fuel}`); continue; }
const fuelW = q / (f.efficiency || 0.85), co2e = fuelW / MMBTU_J * fac; rows.push({ kind: 'fired duty', id, fuel: f.fuel, fuelPower: fuelW, co2e }); total += co2e;
}
for (const [id, f] of Object.entries(electric)) {
const w = Math.abs((res.units[id] || {}).W || 0) + Math.abs((res.units[id] || {}).Q || 0);
if (f.kgCO2ePerKWh == null) { problems.push(`unit ${id}: no electricity factor given (choose the grid's: none is assumed)`); continue; }
const co2e = w / 3.6e6 * f.kgCO2ePerKWh; rows.push({ kind: 'electric', id, co2e }); total += co2e;
}
return { rows, total, perYear: total * 3600 * hours, hours, problems, sources: [GWP_SOURCE, FUEL_SOURCE] };
}
In detail
Method
Carbon balance for complete combustion (each carbon atom gives one CO2); heating values from formation enthalpies; fired duty ÷ efficiency × fuel factor; electric power × the person's grid factor. The file cites IPCC AR5 WG1 Table 8.A.1 for the warming potentials and the US EPA GHG Emission Factors Hub for the fuel factors.
Number types
64-bit numbers.
Limits
Only compounds of C, H, O and N have a heating value. Components without a warming potential in the table count as zero when vented. A fired unit without an efficiency uses 0.85 and the default operating time is 8000 hours a year. The file's header says the fuel factors were typed from the published table and are to be re-read against the current edition before use.
Approach: 64-bit, stated limit
The arithmetic is 64-bit, but the method or the data sets the accuracy: a solver tolerance, a mesh, a step size, a datum shift, a table. The limit is stated where the result is shown.