carbon-calculator

Sustainability requirements demand:

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "carbon-calculator" with this command: npx skills add datadrivenconstruction/ddc_skills_for_ai_agents_in_construction/datadrivenconstruction-ddc-skills-for-ai-agents-in-construction-carbon-calculator

Carbon Calculator

Business Case

Problem Statement

Sustainability requirements demand:

  • Tracking embodied carbon

  • Comparing material options

  • Meeting carbon targets

  • Reporting emissions

Solution

Calculate and track embodied carbon for construction materials using standard emission factors.

Technical Implementation

import pandas as pd from typing import Dict, Any, List, Optional from dataclasses import dataclass from enum import Enum

class MaterialCategory(Enum): CONCRETE = "concrete" STEEL = "steel" ALUMINUM = "aluminum" TIMBER = "timber" BRICK = "brick" GLASS = "glass" INSULATION = "insulation" PLASTIC = "plastic" COPPER = "copper" OTHER = "other"

@dataclass class CarbonFactor: material: str category: MaterialCategory ec_factor: float # kgCO2e per unit unit: str source: str

@dataclass class MaterialInput: material_code: str material_name: str quantity: float unit: str category: MaterialCategory

@dataclass class CarbonResult: material_code: str material_name: str quantity: float unit: str ec_factor: float embodied_carbon: float # kgCO2e category: str

Embodied carbon factors (kgCO2e per unit)

CARBON_FACTORS = { # Concrete 'concrete_c20': CarbonFactor('Concrete C20', MaterialCategory.CONCRETE, 240, 'm3', 'ICE Database'), 'concrete_c30': CarbonFactor('Concrete C30', MaterialCategory.CONCRETE, 290, 'm3', 'ICE Database'), 'concrete_c40': CarbonFactor('Concrete C40', MaterialCategory.CONCRETE, 350, 'm3', 'ICE Database'), 'concrete_c50': CarbonFactor('Concrete C50', MaterialCategory.CONCRETE, 410, 'm3', 'ICE Database'),

# Steel
'steel_rebar': CarbonFactor('Rebar', MaterialCategory.STEEL, 1.99, 'kg', 'ICE Database'),
'steel_section': CarbonFactor('Steel Section', MaterialCategory.STEEL, 1.55, 'kg', 'ICE Database'),
'steel_sheet': CarbonFactor('Steel Sheet', MaterialCategory.STEEL, 2.03, 'kg', 'ICE Database'),
'steel_stainless': CarbonFactor('Stainless Steel', MaterialCategory.STEEL, 6.15, 'kg', 'ICE Database'),

# Aluminum
'aluminum_general': CarbonFactor('Aluminum General', MaterialCategory.ALUMINUM, 9.16, 'kg', 'ICE Database'),
'aluminum_recycled': CarbonFactor('Aluminum Recycled', MaterialCategory.ALUMINUM, 1.81, 'kg', 'ICE Database'),

# Timber
'timber_softwood': CarbonFactor('Softwood Timber', MaterialCategory.TIMBER, 0.31, 'kg', 'ICE Database'),
'timber_hardwood': CarbonFactor('Hardwood Timber', MaterialCategory.TIMBER, 0.46, 'kg', 'ICE Database'),
'timber_glulam': CarbonFactor('Glulam', MaterialCategory.TIMBER, 0.51, 'kg', 'ICE Database'),
'timber_clt': CarbonFactor('CLT', MaterialCategory.TIMBER, 0.44, 'kg', 'ICE Database'),
'timber_plywood': CarbonFactor('Plywood', MaterialCategory.TIMBER, 0.65, 'kg', 'ICE Database'),

# Masonry
'brick_common': CarbonFactor('Common Brick', MaterialCategory.BRICK, 0.24, 'kg', 'ICE Database'),
'block_concrete': CarbonFactor('Concrete Block', MaterialCategory.BRICK, 0.10, 'kg', 'ICE Database'),

# Glass
'glass_float': CarbonFactor('Float Glass', MaterialCategory.GLASS, 1.44, 'kg', 'ICE Database'),
'glass_double': CarbonFactor('Double Glazing', MaterialCategory.GLASS, 35.0, 'm2', 'ICE Database'),

# Insulation
'insul_mineral': CarbonFactor('Mineral Wool', MaterialCategory.INSULATION, 1.28, 'kg', 'ICE Database'),
'insul_eps': CarbonFactor('EPS', MaterialCategory.INSULATION, 3.29, 'kg', 'ICE Database'),
'insul_xps': CarbonFactor('XPS', MaterialCategory.INSULATION, 3.29, 'kg', 'ICE Database'),

# Other
'copper_pipe': CarbonFactor('Copper Pipe', MaterialCategory.COPPER, 2.71, 'kg', 'ICE Database'),
'pvc_pipe': CarbonFactor('PVC Pipe', MaterialCategory.PLASTIC, 3.10, 'kg', 'ICE Database'),

}

class CarbonCalculator: """Calculate embodied carbon for construction."""

def __init__(self, project_name: str):
    self.project_name = project_name
    self.materials: List[MaterialInput] = []
    self.results: List[CarbonResult] = []
    self.custom_factors: Dict[str, CarbonFactor] = {}

def add_custom_factor(self,
                      code: str,
                      name: str,
                      category: MaterialCategory,
                      ec_factor: float,
                      unit: str,
                      source: str = "Custom"):
    """Add custom carbon factor."""

    self.custom_factors[code] = CarbonFactor(
        material=name,
        category=category,
        ec_factor=ec_factor,
        unit=unit,
        source=source
    )

def get_factor(self, material_code: str) -> Optional[CarbonFactor]:
    """Get carbon factor for material."""

    # Check custom first
    if material_code in self.custom_factors:
        return self.custom_factors[material_code]

    # Check standard factors
    code_lower = material_code.lower().replace('-', '_').replace(' ', '_')
    return CARBON_FACTORS.get(code_lower)

def add_material(self,
                 material_code: str,
                 material_name: str,
                 quantity: float,
                 unit: str,
                 category: MaterialCategory = MaterialCategory.OTHER):
    """Add material to calculation."""

    self.materials.append(MaterialInput(
        material_code=material_code,
        material_name=material_name,
        quantity=quantity,
        unit=unit,
        category=category
    ))

def calculate(self) -> List[CarbonResult]:
    """Calculate embodied carbon for all materials."""

    self.results = []

    for mat in self.materials:
        factor = self.get_factor(mat.material_code)

        if factor:
            # Check unit compatibility
            if factor.unit == mat.unit:
                ec = mat.quantity * factor.ec_factor
            else:
                # Assume conversion needed - simplified
                ec = mat.quantity * factor.ec_factor
        else:
            # Use default factor based on category
            default_factors = {
                MaterialCategory.CONCRETE: 300,
                MaterialCategory.STEEL: 1.8,
                MaterialCategory.ALUMINUM: 9.0,
                MaterialCategory.TIMBER: 0.4,
                MaterialCategory.BRICK: 0.2,
                MaterialCategory.GLASS: 1.5,
                MaterialCategory.INSULATION: 2.0,
                MaterialCategory.OTHER: 1.0
            }
            ec_factor = default_factors.get(mat.category, 1.0)
            ec = mat.quantity * ec_factor

        self.results.append(CarbonResult(
            material_code=mat.material_code,
            material_name=mat.material_name,
            quantity=mat.quantity,
            unit=mat.unit,
            ec_factor=factor.ec_factor if factor else 0,
            embodied_carbon=round(ec, 2),
            category=mat.category.value
        ))

    return self.results

def get_total_carbon(self) -> float:
    """Get total embodied carbon (kgCO2e)."""
    return sum(r.embodied_carbon for r in self.results)

def get_carbon_by_category(self) -> Dict[str, float]:
    """Get carbon breakdown by category."""

    by_category = {}
    for r in self.results:
        if r.category not in by_category:
            by_category[r.category] = 0
        by_category[r.category] += r.embodied_carbon

    return {k: round(v, 2) for k, v in by_category.items()}

def compare_alternatives(self,
                          original_code: str,
                          original_qty: float,
                          alternative_code: str,
                          alternative_qty: float) -> Dict[str, Any]:
    """Compare carbon impact of material alternatives."""

    original_factor = self.get_factor(original_code)
    alt_factor = self.get_factor(alternative_code)

    if not original_factor or not alt_factor:
        return {}

    original_carbon = original_qty * original_factor.ec_factor
    alt_carbon = alternative_qty * alt_factor.ec_factor
    savings = original_carbon - alt_carbon

    return {
        'original_material': original_factor.material,
        'original_carbon': round(original_carbon, 2),
        'alternative_material': alt_factor.material,
        'alternative_carbon': round(alt_carbon, 2),
        'carbon_savings': round(savings, 2),
        'savings_percent': round(savings / original_carbon * 100, 1) if original_carbon > 0 else 0
    }

def generate_report(self) -> Dict[str, Any]:
    """Generate carbon report."""

    if not self.results:
        self.calculate()

    total = self.get_total_carbon()
    by_category = self.get_carbon_by_category()

    # Find top contributors
    sorted_results = sorted(self.results, key=lambda x: x.embodied_carbon, reverse=True)
    top_5 = sorted_results[:5]

    # Convert to tonnes
    total_tonnes = total / 1000

    return {
        'project': self.project_name,
        'total_kgCO2e': round(total, 2),
        'total_tCO2e': round(total_tonnes, 2),
        'material_count': len(self.results),
        'by_category': by_category,
        'top_contributors': [
            {
                'material': r.material_name,
                'carbon': r.embodied_carbon,
                'percentage': round(r.embodied_carbon / total * 100, 1) if total > 0 else 0
            }
            for r in top_5
        ]
    }

def suggest_reductions(self) -> List[Dict[str, Any]]:
    """Suggest carbon reduction opportunities."""

    if not self.results:
        self.calculate()

    suggestions = []

    for r in self.results:
        # Steel -> Timber
        if r.category == 'steel' and r.embodied_carbon > 1000:
            suggestions.append({
                'material': r.material_name,
                'current_carbon': r.embodied_carbon,
                'suggestion': 'Consider timber alternative where structurally feasible',
                'potential_reduction': '60-80%'
            })

        # Standard concrete -> Low carbon
        if r.category == 'concrete' and r.embodied_carbon > 5000:
            suggestions.append({
                'material': r.material_name,
                'current_carbon': r.embodied_carbon,
                'suggestion': 'Use low-carbon concrete mix with SCMs',
                'potential_reduction': '20-40%'
            })

        # Virgin aluminum -> Recycled
        if r.category == 'aluminum':
            suggestions.append({
                'material': r.material_name,
                'current_carbon': r.embodied_carbon,
                'suggestion': 'Specify recycled aluminum content',
                'potential_reduction': '70-80%'
            })

    return suggestions

def export_to_excel(self, output_path: str) -> str:
    """Export carbon calculation to Excel."""

    if not self.results:
        self.calculate()

    report = self.generate_report()

    with pd.ExcelWriter(output_path, engine='openpyxl') as writer:
        # Summary
        summary_df = pd.DataFrame([{
            'Project': self.project_name,
            'Total kgCO2e': report['total_kgCO2e'],
            'Total tCO2e': report['total_tCO2e'],
            'Materials': report['material_count']
        }])
        summary_df.to_excel(writer, sheet_name='Summary', index=False)

        # Details
        details_df = pd.DataFrame([
            {
                'Material Code': r.material_code,
                'Material': r.material_name,
                'Quantity': r.quantity,
                'Unit': r.unit,
                'EC Factor': r.ec_factor,
                'Embodied Carbon (kgCO2e)': r.embodied_carbon,
                'Category': r.category
            }
            for r in self.results
        ])
        details_df.to_excel(writer, sheet_name='Materials', index=False)

        # By Category
        cat_df = pd.DataFrame([
            {'Category': k, 'kgCO2e': v}
            for k, v in report['by_category'].items()
        ])
        cat_df.to_excel(writer, sheet_name='By Category', index=False)

        # Suggestions
        suggestions = self.suggest_reductions()
        if suggestions:
            sug_df = pd.DataFrame(suggestions)
            sug_df.to_excel(writer, sheet_name='Reduction Ideas', index=False)

    return output_path

Quick Start

Initialize calculator

calc = CarbonCalculator("Office Building A")

Add materials

calc.add_material("concrete_c30", "Foundation Concrete", 500, "m3", MaterialCategory.CONCRETE) calc.add_material("steel_rebar", "Reinforcement", 50000, "kg", MaterialCategory.STEEL) calc.add_material("steel_section", "Structural Steel", 200000, "kg", MaterialCategory.STEEL) calc.add_material("glass_double", "Facade Glazing", 1500, "m2", MaterialCategory.GLASS)

Calculate

results = calc.calculate()

Get report

report = calc.generate_report() print(f"Total: {report['total_tCO2e']} tCO2e")

Common Use Cases

  1. Compare Alternatives

comparison = calc.compare_alternatives( "steel_section", 100000, "timber_glulam", 80000 ) print(f"Savings: {comparison['savings_percent']}%")

  1. Get Suggestions

suggestions = calc.suggest_reductions() for s in suggestions: print(f"{s['material']}: {s['suggestion']}")

  1. Category Breakdown

by_category = calc.get_carbon_by_category() for cat, carbon in by_category.items(): print(f"{cat}: {carbon:,.0f} kgCO2e")

Resources

  • ICE Database: Inventory of Carbon & Energy

  • DDC Book: Chapter 5.1 - Sustainability Reporting

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Automation

cad-to-data

No summary provided by upstream source.

Repository SourceNeeds Review
Automation

drawing-analyzer

No summary provided by upstream source.

Repository SourceNeeds Review
Automation

dwg-to-excel

No summary provided by upstream source.

Repository SourceNeeds Review
Automation

cost-estimation-resource

No summary provided by upstream source.

Repository SourceNeeds Review