feat: add embodied carbon calculation fields to objets

This commit is contained in:
Björn Steinhagen
2025-02-25 15:37:23 +01:00
parent 9509100f30
commit f19e1f3a3c
5 changed files with 147 additions and 23 deletions
+118 -1
View File
@@ -224,6 +224,119 @@ class RevitCarbonAnalyzer:
# Calculate carbon
try:
carbon_results = self.carbon_calculator.calculate_carbon(processed_element)
# Initialize Embodied Carbon Calculation dictionary
embodied_carbon_data = {}
for material_name, result in carbon_results.items():
# Create a dictionary for each material instead of an array
material_data = {}
if result.category == "Wood":
# For timber - use name/value/units format as dictionary entries
material_data = {
"volume": {
"name": "volume",
"value": result.quantity,
"units": "",
},
"database": {
"name": "database",
"value": result.database,
"units": None,
},
"ecf": {
"name": "ecf",
"value": result.factor,
"units": "kgCO₂e/m³",
},
"embodied carbon": {
"name": "embodied carbon",
"value": result.total_carbon,
"units": "kgCO₂e",
},
}
elif result.category == "Concrete":
# For concrete (include both concrete and reinforcement)
material_data = {
"volume": {
"name": "volume",
"value": result.concrete_volume,
"units": "",
},
"database": {
"name": "database",
"value": result.database,
"units": None,
},
"ecf": {
"name": "ecf",
"value": result.factor,
"units": "kgCO₂e/m³",
},
"concrete carbon": {
"name": "concrete carbon",
"value": result.concrete_carbon,
"units": "kgCO₂e",
},
"reinforcement mass": {
"name": "reinforcement mass",
"value": result.reinforcement_mass,
"units": "kg",
},
"reinforcement rate": {
"name": "reinforcement rate",
"value": result.reinforcement_rate,
"units": "kg/m³",
},
"reinforcement ecf": {
"name": "reinforcement ecf",
"value": result.reinforcement_factor,
"units": "kgCO₂e/kg",
},
"reinforcement carbon": {
"name": "reinforcement carbon",
"value": result.reinforcement_carbon,
"units": "kgCO₂e",
},
"embodied carbon": {
"name": "embodied carbon",
"value": result.total_carbon,
"units": "kgCO₂e",
},
}
elif result.category == "Metal":
# For metal
material_data = {
"mass": {
"name": "mass",
"value": result.quantity,
"units": "kg",
},
"database": {
"name": "database",
"value": result.database,
"units": None,
},
"ecf": {
"name": "ecf",
"value": result.factor,
"units": "kgCO₂e/kg",
},
"embodied carbon": {
"name": "embodied carbon",
"value": result.total_carbon,
"units": "kgCO₂e",
},
}
# Add this material's data to the main dictionary
embodied_carbon_data[material_name] = material_data
# Attach the data to the original element
if hasattr(element, "properties"):
element.properties["Embodied Carbon Calculation"] = embodied_carbon_data
return {
"id": element_id,
"status": "processed",
@@ -234,7 +347,6 @@ class RevitCarbonAnalyzer:
"name": m.properties.name,
"type": m.type.value,
"volume": m.properties.volume,
# Add other material properties as needed
}
for m in processed_element.materials
],
@@ -371,6 +483,11 @@ def automate_function(
"\nNOTE: All materials successfully matched with emission factors."
)
# Upload mutated model
automate_context.create_new_version_in_project(
model_root, f"{commit_root.branchName}_embodied_carbon"
)
# Mark success with detailed message
automate_context.mark_run_success(success_message)
@@ -12,9 +12,9 @@ class ConcreteEmissionDatabase(EmissionFactorDatabase):
super().__init__()
self._database_name = database_name
self._factors = {}
self._init_factors()
self._load_emission_factors_from_database()
def _init_factors(self):
def _load_emission_factors_from_database(self):
"""Initialize factors based on the specific database."""
# Define mappings from database type to strength values
database_strength_values = {
-11
View File
@@ -14,14 +14,3 @@ class EmissionFactor:
valid_until: Optional[str] = None
manufacturer: Optional[str] = None
plant_location: Optional[str] = None
@dataclass
class CarbonResult:
"""Result of a carbon calculation"""
material_name: str
emission_factor: EmissionFactor
quantity: float
total_carbon: float
category: str
+14 -1
View File
@@ -37,8 +37,21 @@ class BuildingElement:
materials: List[Material]
carbon_data: Optional[Dict] = None
@dataclass
class CarbonResult:
factor: float # kgCO2e/kg for metals, kgCO2e/m3 for wood
total_carbon: float # kgCO2e
category: str
category: str
# Additional fields for detailed output
quantity: float = None # volume (m³) for concrete/wood, mass (kg) for metal
database: str = None # database source
# Concrete-specific fields
concrete_volume: float = None # m³
concrete_carbon: float = None # kgCO2e
reinforcement_mass: float = None # kg
reinforcement_rate: float = None # kg/m³
reinforcement_factor: float = None # kgCO2e/kg
reinforcement_carbon: float = None # kgCO2e
+13 -8
View File
@@ -121,6 +121,8 @@ class CarbonCalculator:
factor=factor.value,
total_carbon=material.mass * factor.value,
category="Metal",
quantity=material.mass,
database=self._steel_database,
)
def _calculate_wood_carbon(self, material: Material) -> CarbonResult:
@@ -148,6 +150,8 @@ class CarbonCalculator:
factor=factor.value,
total_carbon=material.properties.volume * factor.value,
category="Wood",
quantity=material.properties.volume,
database=self._timber_database,
)
def _calculate_concrete_carbon(
@@ -220,19 +224,20 @@ class CarbonCalculator:
total_carbon = concrete_carbon + reinforcement_carbon
# Create result with additional metadata
result = CarbonResult(
return CarbonResult(
factor=concrete_factor.value,
total_carbon=total_carbon,
category="Concrete",
quantity=concrete_volume,
database=self._concrete_database,
concrete_volume=concrete_volume,
concrete_carbon=concrete_carbon,
reinforcement_mass=reinforcement_mass,
reinforcement_rate=reinforcement_rate,
reinforcement_factor=rebar_factor.value,
reinforcement_carbon=reinforcement_carbon,
)
# TODO: Add extra metadata (not in original CarbonResult class, would need extension)
# TODO: result.concrete_carbon = concrete_carbon
# TODO: result.reinforcement_carbon = reinforcement_carbon
# TODO: result.reinforcement_rate = reinforcement_rate
return result
@staticmethod
def _map_element_category_to_concrete_type(
element_category: ElementCategory,