<< All versions
Skill v1.0.1
currentAutomated scan100/100datadrivenconstruction/ddc_skills_for_ai_agents_in_construction/carbon-calculator
1 files
──Details
PublishedSeptember 29, 2026 at 06:12 AM
Content Hashsha256:f97b87df60d84553...
Git SHAce45bbfbdd63
Bump Typepatch
──Files
Files (1 file, 14.4 KB)
SKILL.md14.4 KBactive
SKILL.md · 420 lines · 14.4 KB
version: "1.0.1" name: "carbon-calculator" description: "Calculate embodied carbon in construction materials. Track CO2 emissions, compare alternatives, and generate sustainability reports." homepage: "https://datadrivenconstruction.io" metadata: {"openclaw": {"emoji": "🌱", "os": ["darwin", "linux", "win32"], "homepage": "https://datadrivenconstruction.io", "requires": {"bins": ["python3"]}}}
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
python
import pandas as pdfrom typing import Dict, Any, List, Optionalfrom dataclasses import dataclassfrom enum import Enumclass MaterialCategory(Enum):CONCRETE = "concrete"STEEL = "steel"ALUMINUM = "aluminum"TIMBER = "timber"BRICK = "brick"GLASS = "glass"INSULATION = "insulation"PLASTIC = "plastic"COPPER = "copper"OTHER = "other"@dataclassclass CarbonFactor:material: strcategory: MaterialCategoryec_factor: float # kgCO2e per unitunit: strsource: str@dataclassclass MaterialInput:material_code: strmaterial_name: strquantity: floatunit: strcategory: MaterialCategory@dataclassclass CarbonResult:material_code: strmaterial_name: strquantity: floatunit: strec_factor: floatembodied_carbon: float # kgCO2ecategory: 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_nameself.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 firstif material_code in self.custom_factors:return self.custom_factors[material_code]# Check standard factorscode_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 compatibilityif factor.unit == mat.unit:ec = mat.quantity * factor.ec_factorelse:# Assume conversion needed - simplifiedec = mat.quantity * factor.ec_factorelse:# Use default factor based on categorydefault_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_factorself.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.resultsdef 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] = 0by_category[r.category] += r.embodied_carbonreturn {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_factoralt_carbon = alternative_qty * alt_factor.ec_factorsavings = original_carbon - alt_carbonreturn {'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 contributorssorted_results = sorted(self.results, key=lambda x: x.embodied_carbon, reverse=True)top_5 = sorted_results[:5]# Convert to tonnestotal_tonnes = total / 1000return {'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 -> Timberif 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 carbonif 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 -> Recycledif r.category == 'aluminum':suggestions.append({'material': r.material_name,'current_carbon': r.embodied_carbon,'suggestion': 'Specify recycled aluminum content','potential_reduction': '70-80%'})return suggestionsdef 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:# Summarysummary_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)# Detailsdetails_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 Categorycat_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)# Suggestionssuggestions = 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
python
# Initialize calculatorcalc = CarbonCalculator("Office Building A")# Add materialscalc.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)# Calculateresults = calc.calculate()# Get reportreport = calc.generate_report()print(f"Total: {report['total_tCO2e']} tCO2e")
Common Use Cases
1. Compare Alternatives
python
comparison = calc.compare_alternatives("steel_section", 100000,"timber_glulam", 80000)print(f"Savings: {comparison['savings_percent']}%")
2. Get Suggestions
python
suggestions = calc.suggest_reductions()for s in suggestions:print(f"{s['material']}: {s['suggestion']}")
3. Category Breakdown
python
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