/** * Carbon Equivalencies - EPA/DEFRA/IMO 2024 Verified Conversion Factors * Ported from frontend src/utils/carbonEquivalencies.ts and impactSelector.ts */ // Carbon equivalency conversion factors (units per metric ton of CO2e) export const CARBON_EQUIVALENCIES = { // TRANSPORTATION (EPA 2024) MILES_DRIVEN_AVG_CAR: 2560, GALLONS_GASOLINE: 113, // AVIATION (DEFRA 2024) FLIGHT_KM_ECONOMY_SHORT: 6667, FLIGHT_KM_ECONOMY_LONG: 7692, // NATURAL (EPA 2024) TREE_SEEDLINGS_10YR: 16.7, FOREST_ACRES_1YR: 1.0, FOREST_ACRES_10YR: 1.32, // ENERGY (EPA 2024) ELECTRICITY_KWH: 2540, HOME_ENERGY_YEARS: 0.134, BARRELS_OIL: 2.33, // YACHT-SPECIFIC (IMO 2024) MGO_LITERS_AVOIDED: 373, MGO_TONNES_AVOIDED: 0.312, CRUISING_HOURS_60M: 1.24, SUPERYACHT_NAUTICAL_MILES: 149, SHORE_POWER_DAYS: 25.4, // LIFESTYLE SMARTPHONE_CHARGES: 115000, POUNDS_COAL_BURNED: 1000, }; // Comparison definitions with emoji icons (email-compatible) const COMPARISON_DEFINITIONS = { MILES_DRIVEN: { icon: '🚗', unit: 'miles', label: 'Miles driven in an average car', }, GALLONS_GASOLINE: { icon: '⛽', unit: 'gallons', label: 'Gallons of gasoline not burned', }, FLIGHT_KM_SHORT: { icon: '✈️', unit: 'passenger-km', label: 'Short-haul flight distance (economy)', }, FLIGHT_KM_LONG: { icon: '🛫', unit: 'passenger-km', label: 'Long-haul flight distance (economy)', }, TREE_SEEDLINGS: { icon: '🌲', unit: 'trees', label: 'Tree seedlings grown for 10 years', }, FOREST_ACRES_1YR: { icon: '🌳', unit: 'acres', label: 'Acres of forest preserved for 1 year', }, FOREST_ACRES_10YR: { icon: '🌳', unit: 'acres', label: 'Acres of forest carbon sequestration over 10 years', }, ELECTRICITY_KWH: { icon: '⚡', unit: 'kWh', label: 'Kilowatt-hours of electricity', }, HOME_ENERGY_YEARS: { icon: '🏠', unit: 'home-years', label: 'Years of home electricity use', }, BARRELS_OIL: { icon: '💧', unit: 'barrels', label: 'Barrels of oil not consumed', }, MGO_LITERS: { icon: '🌊', unit: 'liters', label: 'Liters of Marine Gas Oil avoided', }, MGO_TONNES: { icon: '💧', unit: 'tonnes', label: 'Tonnes of Marine Gas Oil avoided', }, CRUISING_HOURS: { icon: '⚓', unit: 'hours', label: 'Hours of 60m yacht cruising avoided', }, SUPERYACHT_NAUTICAL_MILES: { icon: '🚢', unit: 'nautical miles', label: 'Nautical miles of superyacht voyaging', }, SHORE_POWER_DAYS: { icon: '🔋', unit: 'days', label: 'Days of shore power for large yacht', }, SMARTPHONE_CHARGES: { icon: '📱', unit: 'charges', label: 'Smartphone charges', }, POUNDS_COAL: { icon: '🔥', unit: 'pounds', label: 'Pounds of coal not burned', }, }; // Smart scaling ranges - different comparisons for different CO2 amounts const SCALING_RANGES = [ { minTons: 0, maxTons: 0.1, comparisonKeys: ['MILES_DRIVEN', 'SMARTPHONE_CHARGES', 'TREE_SEEDLINGS'], }, { minTons: 0.1, maxTons: 1, comparisonKeys: ['MILES_DRIVEN', 'TREE_SEEDLINGS', 'GALLONS_GASOLINE'], }, { minTons: 1, maxTons: 5, comparisonKeys: ['FLIGHT_KM_SHORT', 'TREE_SEEDLINGS', 'ELECTRICITY_KWH'], }, { minTons: 5, maxTons: 20, comparisonKeys: ['FLIGHT_KM_LONG', 'FOREST_ACRES_1YR', 'MGO_LITERS'], }, { minTons: 20, maxTons: 100, comparisonKeys: ['CRUISING_HOURS', 'FOREST_ACRES_1YR', 'HOME_ENERGY_YEARS'], }, { minTons: 100, maxTons: Infinity, comparisonKeys: ['FOREST_ACRES_10YR', 'CRUISING_HOURS', 'SUPERYACHT_NAUTICAL_MILES'], }, ]; // Factor mapping for conversion const FACTOR_MAP = { MILES_DRIVEN: CARBON_EQUIVALENCIES.MILES_DRIVEN_AVG_CAR, GALLONS_GASOLINE: CARBON_EQUIVALENCIES.GALLONS_GASOLINE, FLIGHT_KM_SHORT: CARBON_EQUIVALENCIES.FLIGHT_KM_ECONOMY_SHORT, FLIGHT_KM_LONG: CARBON_EQUIVALENCIES.FLIGHT_KM_ECONOMY_LONG, TREE_SEEDLINGS: CARBON_EQUIVALENCIES.TREE_SEEDLINGS_10YR, FOREST_ACRES_1YR: CARBON_EQUIVALENCIES.FOREST_ACRES_1YR, FOREST_ACRES_10YR: CARBON_EQUIVALENCIES.FOREST_ACRES_10YR, ELECTRICITY_KWH: CARBON_EQUIVALENCIES.ELECTRICITY_KWH, HOME_ENERGY_YEARS: CARBON_EQUIVALENCIES.HOME_ENERGY_YEARS, BARRELS_OIL: CARBON_EQUIVALENCIES.BARRELS_OIL, MGO_LITERS: CARBON_EQUIVALENCIES.MGO_LITERS_AVOIDED, MGO_TONNES: CARBON_EQUIVALENCIES.MGO_TONNES_AVOIDED, CRUISING_HOURS: CARBON_EQUIVALENCIES.CRUISING_HOURS_60M, SUPERYACHT_NAUTICAL_MILES: CARBON_EQUIVALENCIES.SUPERYACHT_NAUTICAL_MILES, SHORE_POWER_DAYS: CARBON_EQUIVALENCIES.SHORE_POWER_DAYS, SMARTPHONE_CHARGES: CARBON_EQUIVALENCIES.SMARTPHONE_CHARGES, POUNDS_COAL: CARBON_EQUIVALENCIES.POUNDS_COAL_BURNED, }; /** * Calculate equivalency value */ function calculateEquivalency(tons, factor) { return tons * factor; } /** * Format large numbers with appropriate precision */ function formatEquivalencyValue(value) { if (value < 0.01) { return value.toExponential(2); } else if (value < 1) { return value.toFixed(2); } else if (value < 100) { return value.toFixed(1); } else if (value < 1000) { return Math.round(value).toLocaleString(); } else { return Math.round(value).toLocaleString(); } } /** * Select the most appropriate comparisons for the given CO2 amount * @param {number} tons - Metric tons of CO2e to offset * @param {number} count - Number of comparisons to return (default: 3) * @returns {Array} Array of carbon comparisons with calculated values */ export function selectComparisons(tons, count = 3) { // Find the appropriate range for this amount const range = SCALING_RANGES.find( (r) => tons >= r.minTons && tons < r.maxTons ); if (!range) { console.warn(`No comparison range found for ${tons} tons, using default`); return getDefaultComparisons(tons, count); } // Get the comparison definitions for this range const comparisons = range.comparisonKeys .slice(0, count) .map((key) => { const definition = COMPARISON_DEFINITIONS[key]; const factor = FACTOR_MAP[key]; const value = calculateEquivalency(tons, factor); return { ...definition, value: formatEquivalencyValue(value), }; }); return comparisons; } /** * Get default comparisons when no range matches */ function getDefaultComparisons(tons, count) { const defaultKeys = ['MILES_DRIVEN', 'TREE_SEEDLINGS', 'ELECTRICITY_KWH']; return defaultKeys.slice(0, count).map((key) => { const definition = COMPARISON_DEFINITIONS[key]; const factor = FACTOR_MAP[key]; const value = calculateEquivalency(tons, factor); return { ...definition, value: formatEquivalencyValue(value), }; }); }