fix: swallowed exceptions
build and deploy Speckle functions / publish-automate-function-version (push) Has been cancelled
build and deploy Speckle functions / publish-automate-function-version (push) Has been cancelled
This commit is contained in:
@@ -156,7 +156,7 @@ class RevitCarbonAnalyzer:
|
|||||||
results = {
|
results = {
|
||||||
"processed_elements": [],
|
"processed_elements": [],
|
||||||
"skipped_elements": [],
|
"skipped_elements": [],
|
||||||
"warning_elements": [], # For invalid elements
|
"warning_elements": [],
|
||||||
"errors": [],
|
"errors": [],
|
||||||
"total_carbon": 0.0,
|
"total_carbon": 0.0,
|
||||||
"missing_factors": {"timber": [], "steel": [], "concrete": []},
|
"missing_factors": {"timber": [], "steel": [], "concrete": []},
|
||||||
@@ -243,7 +243,19 @@ class RevitCarbonAnalyzer:
|
|||||||
|
|
||||||
# Calculate carbon
|
# Calculate carbon
|
||||||
try:
|
try:
|
||||||
carbon_results = self.carbon_calculator.calculate_carbon(processed_element)
|
carbon_results, material_errors = self.carbon_calculator.calculate_carbon(
|
||||||
|
processed_element
|
||||||
|
)
|
||||||
|
|
||||||
|
if not carbon_results:
|
||||||
|
error_details = "; ".join(
|
||||||
|
[f"{e['material']}: {e['error']}" for e in material_errors]
|
||||||
|
)
|
||||||
|
return {
|
||||||
|
"id": element_id,
|
||||||
|
"status": "error",
|
||||||
|
"reason": f"No carbon could be calculated: {error_details}",
|
||||||
|
}
|
||||||
|
|
||||||
# Initialize Embodied Carbon Calculation dictionary
|
# Initialize Embodied Carbon Calculation dictionary
|
||||||
embodied_carbon_data = {}
|
embodied_carbon_data = {}
|
||||||
@@ -265,13 +277,13 @@ class RevitCarbonAnalyzer:
|
|||||||
"value": result.database,
|
"value": result.database,
|
||||||
"units": None,
|
"units": None,
|
||||||
},
|
},
|
||||||
"ecf": {
|
"embodiedCarbonFactor": {
|
||||||
"name": "ecf",
|
"name": "embodiedCarbonFactor",
|
||||||
"value": result.factor,
|
"value": result.factor,
|
||||||
"units": "kgCO₂e/m³",
|
"units": "kgCO₂e/m³",
|
||||||
},
|
},
|
||||||
"embodied carbon": {
|
"embodiedCarbon": {
|
||||||
"name": "embodied carbon",
|
"name": "embodiedCarbon",
|
||||||
"value": result.total_carbon,
|
"value": result.total_carbon,
|
||||||
"units": "kgCO₂e",
|
"units": "kgCO₂e",
|
||||||
},
|
},
|
||||||
@@ -279,8 +291,8 @@ class RevitCarbonAnalyzer:
|
|||||||
elif result.category == "Concrete":
|
elif result.category == "Concrete":
|
||||||
# For concrete (include both concrete and reinforcement)
|
# For concrete (include both concrete and reinforcement)
|
||||||
material_data = {
|
material_data = {
|
||||||
"volume": {
|
"concreteVolume": {
|
||||||
"name": "volume",
|
"name": "concreteVolume",
|
||||||
"value": result.concrete_volume,
|
"value": result.concrete_volume,
|
||||||
"units": "m³",
|
"units": "m³",
|
||||||
},
|
},
|
||||||
@@ -289,38 +301,38 @@ class RevitCarbonAnalyzer:
|
|||||||
"value": result.database,
|
"value": result.database,
|
||||||
"units": None,
|
"units": None,
|
||||||
},
|
},
|
||||||
"ecf": {
|
"concreteEmbodiedCarbonFactor": {
|
||||||
"name": "ecf",
|
"name": "concreteEmbodiedCarbonFactor",
|
||||||
"value": result.factor,
|
"value": result.factor,
|
||||||
"units": "kgCO₂e/m³",
|
"units": "kgCO₂e/m³",
|
||||||
},
|
},
|
||||||
"concrete carbon": {
|
"concreteEmbodiedCarbon": {
|
||||||
"name": "concrete carbon",
|
"name": "concreteEmbodiedCarbon",
|
||||||
"value": result.concrete_carbon,
|
"value": result.concrete_carbon,
|
||||||
"units": "kgCO₂e",
|
"units": "kgCO₂e",
|
||||||
},
|
},
|
||||||
"reinforcement mass": {
|
"reinforcementMass": {
|
||||||
"name": "reinforcement mass",
|
"name": "reinforcementMass",
|
||||||
"value": result.reinforcement_mass,
|
"value": result.reinforcement_mass,
|
||||||
"units": "kg",
|
"units": "kg",
|
||||||
},
|
},
|
||||||
"reinforcement rate": {
|
"reinforcementRate": {
|
||||||
"name": "reinforcement rate",
|
"name": "reinforcementRate",
|
||||||
"value": result.reinforcement_rate,
|
"value": result.reinforcement_rate,
|
||||||
"units": "kg/m³",
|
"units": "kg/m³",
|
||||||
},
|
},
|
||||||
"reinforcement ecf": {
|
"reinforcementEmbodiedCarbonFactor": {
|
||||||
"name": "reinforcement ecf",
|
"name": "reinforcementEmbodiedCarbonFactor",
|
||||||
"value": result.reinforcement_factor,
|
"value": result.reinforcement_factor,
|
||||||
"units": "kgCO₂e/kg",
|
"units": "kgCO₂e/kg",
|
||||||
},
|
},
|
||||||
"reinforcement carbon": {
|
"reinforcementEmbodiedCarbon": {
|
||||||
"name": "reinforcement carbon",
|
"name": "reinforcementEmbodiedCarbon",
|
||||||
"value": result.reinforcement_carbon,
|
"value": result.reinforcement_carbon,
|
||||||
"units": "kgCO₂e",
|
"units": "kgCO₂e",
|
||||||
},
|
},
|
||||||
"embodied carbon": {
|
"embodiedCarbon": {
|
||||||
"name": "embodied carbon",
|
"name": "embodiedCarbon",
|
||||||
"value": result.total_carbon,
|
"value": result.total_carbon,
|
||||||
"units": "kgCO₂e",
|
"units": "kgCO₂e",
|
||||||
},
|
},
|
||||||
@@ -338,13 +350,13 @@ class RevitCarbonAnalyzer:
|
|||||||
"value": result.database,
|
"value": result.database,
|
||||||
"units": None,
|
"units": None,
|
||||||
},
|
},
|
||||||
"ecf": {
|
"embodiedCarbonFactor": {
|
||||||
"name": "ecf",
|
"name": "embodiedCarbonFactor",
|
||||||
"value": result.factor,
|
"value": result.factor,
|
||||||
"units": "kgCO₂e/kg",
|
"units": "kgCO₂e/kg",
|
||||||
},
|
},
|
||||||
"embodied carbon": {
|
"embodiedCarbon": {
|
||||||
"name": "embodied carbon",
|
"name": "embodiedCarbon",
|
||||||
"value": result.total_carbon,
|
"value": result.total_carbon,
|
||||||
"units": "kgCO₂e",
|
"units": "kgCO₂e",
|
||||||
},
|
},
|
||||||
@@ -357,9 +369,9 @@ class RevitCarbonAnalyzer:
|
|||||||
if hasattr(element, "properties"):
|
if hasattr(element, "properties"):
|
||||||
element.properties["Embodied Carbon Calculation"] = embodied_carbon_data
|
element.properties["Embodied Carbon Calculation"] = embodied_carbon_data
|
||||||
|
|
||||||
return {
|
element_result = {
|
||||||
"id": element_id,
|
"id": element_id,
|
||||||
"status": "processed",
|
"status": "processed" if not material_errors else "warning",
|
||||||
"level": processed_element.level,
|
"level": processed_element.level,
|
||||||
"category": processed_element.category,
|
"category": processed_element.category,
|
||||||
"materials": [
|
"materials": [
|
||||||
@@ -373,11 +385,21 @@ class RevitCarbonAnalyzer:
|
|||||||
"carbon_results": carbon_results,
|
"carbon_results": carbon_results,
|
||||||
"total_carbon": sum(r.total_carbon for r in carbon_results.values()),
|
"total_carbon": sum(r.total_carbon for r in carbon_results.values()),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# If there were material errors, include them in the result
|
||||||
|
if material_errors:
|
||||||
|
element_result["material_errors"] = material_errors
|
||||||
|
element_result[
|
||||||
|
"reason"
|
||||||
|
] = f"Issues with {len(material_errors)} materials"
|
||||||
|
|
||||||
|
return element_result
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
return {
|
return {
|
||||||
"id": element_id,
|
"id": element_id,
|
||||||
"status": "error",
|
"status": "error",
|
||||||
"error": f"Carbon calculation failed: {str(e)}",
|
"reason": f"Carbon calculation failed: {str(e)}",
|
||||||
}
|
}
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@@ -485,8 +507,8 @@ def automate_function(
|
|||||||
element_id,
|
element_id,
|
||||||
key,
|
key,
|
||||||
"{:0.2f} {}".format(
|
"{:0.2f} {}".format(
|
||||||
value["embodied carbon"]["value"],
|
value["embodiedCarbon"]["value"],
|
||||||
value["embodied carbon"]["units"],
|
value["embodiedCarbon"]["units"],
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
@@ -550,9 +572,9 @@ def automate_function(
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Upload mutated model
|
# Upload mutated model
|
||||||
# automate_context.create_new_version_in_project(
|
automate_context.create_new_version_in_project(
|
||||||
# model_root, f"{commit_root.branchName}_embodied_carbon"
|
model_root, f"{commit_root.branchName}_embodied_carbon"
|
||||||
# )
|
)
|
||||||
|
|
||||||
# Mark success with detailed message
|
# Mark success with detailed message
|
||||||
automate_context.mark_run_success(success_message)
|
automate_context.mark_run_success(success_message)
|
||||||
@@ -574,10 +596,21 @@ def _process_automation_results(
|
|||||||
"""Process results and attach them to the automation context."""
|
"""Process results and attach them to the automation context."""
|
||||||
# Process each category and attach to objects
|
# Process each category and attach to objects
|
||||||
|
|
||||||
# Successes
|
# Successes with gradient metadata
|
||||||
if results["processed_elements"]:
|
if results["processed_elements"]:
|
||||||
|
# Create a dictionary mapping element IDs to their total carbon values
|
||||||
|
embodied_carbon_values = {}
|
||||||
|
|
||||||
|
# Extract the total carbon for each element
|
||||||
|
for element in results["processed_elements"]:
|
||||||
|
element_id = element["id"]
|
||||||
|
# The total carbon is already calculated and stored in each element result
|
||||||
|
total_carbon = element["total_carbon"]
|
||||||
|
embodied_carbon_values[element_id] = {"gradientValue": total_carbon}
|
||||||
|
|
||||||
automate_context.attach_success_to_objects(
|
automate_context.attach_success_to_objects(
|
||||||
category="Carbon Analysis",
|
category="Carbon Analysis",
|
||||||
|
metadata={"gradient": True, "gradientValues": embodied_carbon_values},
|
||||||
object_ids=[e["id"] for e in results["processed_elements"]],
|
object_ids=[e["id"] for e in results["processed_elements"]],
|
||||||
message="Carbon calculations completed successfully for these elements!",
|
message="Carbon calculations completed successfully for these elements!",
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -12,9 +12,27 @@ class MaterialAliasService:
|
|||||||
"glue laminated timber",
|
"glue laminated timber",
|
||||||
"glued laminated timber",
|
"glued laminated timber",
|
||||||
"glulam beam",
|
"glulam beam",
|
||||||
|
"GL36h",
|
||||||
|
"GL36h(1)",
|
||||||
|
"GL24h",
|
||||||
|
"GL28h",
|
||||||
|
"GL30h",
|
||||||
|
"GL32h",
|
||||||
|
"GL36c",
|
||||||
|
"GL36c(1)",
|
||||||
|
"GL24c",
|
||||||
|
"GL28c",
|
||||||
|
"GL30c",
|
||||||
|
"GL32c",
|
||||||
|
"softwood",
|
||||||
],
|
],
|
||||||
"lvl": ["laminated veneer lumber"],
|
"lvl": ["laminated veneer lumber"],
|
||||||
"softwood lumber": ["dimensional lumber", "sawn lumber", "softwood"],
|
"softwood lumber": [
|
||||||
|
"dimensional lumber",
|
||||||
|
"sawn lumber",
|
||||||
|
"softwood",
|
||||||
|
"FE_Wood - Dimensional Lumber",
|
||||||
|
],
|
||||||
"softwood plywood": ["plywood", "softwood ply"],
|
"softwood plywood": ["plywood", "softwood ply"],
|
||||||
"oriented strand board": ["osb", "osb board"],
|
"oriented strand board": ["osb", "osb board"],
|
||||||
"glt/nlt/dlt": [
|
"glt/nlt/dlt": [
|
||||||
@@ -41,7 +59,7 @@ class MaterialAliasService:
|
|||||||
"rebar": ["reinforcing bar", "reinforcement"],
|
"rebar": ["reinforcing bar", "reinforcement"],
|
||||||
"owsj": ["open web steel joist", "steel joist"],
|
"owsj": ["open web steel joist", "steel joist"],
|
||||||
"fasteners": ["bolts", "screws", "nails", "rivets"],
|
"fasteners": ["bolts", "screws", "nails", "rivets"],
|
||||||
"metal deck": ["deck", "decking"],
|
"metal deck": ["deck", "decking", "metal - decking"],
|
||||||
}
|
}
|
||||||
|
|
||||||
self._concrete_aliases = {
|
self._concrete_aliases = {
|
||||||
|
|||||||
@@ -45,9 +45,12 @@ class CarbonCalculator:
|
|||||||
self._missing_steel_factors = set()
|
self._missing_steel_factors = set()
|
||||||
self._missing_concrete_factors = set()
|
self._missing_concrete_factors = set()
|
||||||
|
|
||||||
def calculate_carbon(self, element: BuildingElement) -> Dict[str, CarbonResult]:
|
def calculate_carbon(
|
||||||
"""Calculate carbon emissions for an element's materials."""
|
self, element: BuildingElement
|
||||||
|
) -> tuple[Dict[str, CarbonResult], List[Dict[str, str]]]:
|
||||||
|
"""Calculate carbon emissions for an element's materials and return results and errors."""
|
||||||
results = {}
|
results = {}
|
||||||
|
errors = []
|
||||||
|
|
||||||
for material in element.materials:
|
for material in element.materials:
|
||||||
try:
|
try:
|
||||||
@@ -77,11 +80,13 @@ class CarbonCalculator:
|
|||||||
)
|
)
|
||||||
self._missing_concrete_factors.add(f"{strength}_{element_type}")
|
self._missing_concrete_factors.add(f"{strength}_{element_type}")
|
||||||
|
|
||||||
print(
|
# Store error with material name instead of just printing
|
||||||
f"Error calculating carbon for {material.properties.name}: {str(e)}"
|
error_msg = (
|
||||||
|
f"No emission factor found for {material.properties.name}: {str(e)}"
|
||||||
)
|
)
|
||||||
|
errors.append({"material": material.properties.name, "error": str(e)})
|
||||||
|
|
||||||
return results
|
return results, errors
|
||||||
|
|
||||||
def _calculate_material_carbon(
|
def _calculate_material_carbon(
|
||||||
self, material: Material, element_category: Optional[ElementCategory] = None
|
self, material: Material, element_category: Optional[ElementCategory] = None
|
||||||
@@ -102,8 +107,6 @@ class CarbonCalculator:
|
|||||||
|
|
||||||
def _calculate_metal_carbon(self, material: Material) -> CarbonResult:
|
def _calculate_metal_carbon(self, material: Material) -> CarbonResult:
|
||||||
"""Calculate carbon emissions for metal."""
|
"""Calculate carbon emissions for metal."""
|
||||||
if not material.mass:
|
|
||||||
raise ValueError("Mass required for metal carbon calculation")
|
|
||||||
|
|
||||||
# Get factor from cache or registry
|
# Get factor from cache or registry
|
||||||
if material.grade not in self._steel_factors_cache:
|
if material.grade not in self._steel_factors_cache:
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ class ElementProcessor:
|
|||||||
"Objects.Geometry.Circle",
|
"Objects.Geometry.Circle",
|
||||||
]
|
]
|
||||||
|
|
||||||
SKIP_FAMILIES = ["Grid", "JS_SF_Centerline Only"]
|
SKIP_FAMILIES = ["Grid", "JS_SF_Centerline Only", "none"]
|
||||||
|
|
||||||
def __init__(self, material_processor: MaterialProcessor, logger: Logging):
|
def __init__(self, material_processor: MaterialProcessor, logger: Logging):
|
||||||
self.material_processor = material_processor
|
self.material_processor = material_processor
|
||||||
@@ -108,7 +108,7 @@ class ElementProcessor:
|
|||||||
properties = getattr(element, "properties")
|
properties = getattr(element, "properties")
|
||||||
material_quantities = properties["Material Quantities"]
|
material_quantities = properties["Material Quantities"]
|
||||||
|
|
||||||
for material_data in material_quantities.values(): # Added .values()
|
for material_data in material_quantities.values():
|
||||||
try:
|
try:
|
||||||
material = self.material_processor.process_material(material_data)
|
material = self.material_processor.process_material(material_data)
|
||||||
materials.append(material)
|
materials.append(material)
|
||||||
|
|||||||
@@ -35,9 +35,13 @@ class MaterialProcessor:
|
|||||||
"""Process materials with structural assets."""
|
"""Process materials with structural assets."""
|
||||||
if "concrete" in props.name.lower():
|
if "concrete" in props.name.lower():
|
||||||
return self._process_concrete(props)
|
return self._process_concrete(props)
|
||||||
elif "steel" in props.name.lower():
|
elif "steel" in props.name.lower() or "metal" in props.name.lower():
|
||||||
return self._process_steel(props)
|
return self._process_steel(props)
|
||||||
elif "clt" in props.name.lower() or "timber" in props.name.lower():
|
elif (
|
||||||
|
"clt" in props.name.lower()
|
||||||
|
or "timber" in props.name.lower()
|
||||||
|
or "glulam" in props.name.lower()
|
||||||
|
):
|
||||||
return Material(type=MaterialType.WOOD, properties=props)
|
return Material(type=MaterialType.WOOD, properties=props)
|
||||||
else:
|
else:
|
||||||
raise ValueError(f"Unknown high-grade material: {props.name}")
|
raise ValueError(f"Unknown high-grade material: {props.name}")
|
||||||
@@ -60,7 +64,7 @@ class MaterialProcessor:
|
|||||||
mass=mass,
|
mass=mass,
|
||||||
grade="default_steel",
|
grade="default_steel",
|
||||||
)
|
)
|
||||||
elif "clt" in name or "timber" in name:
|
elif "clt" in name or "timber" in name or "wood" in name:
|
||||||
return Material(type=MaterialType.WOOD, properties=props)
|
return Material(type=MaterialType.WOOD, properties=props)
|
||||||
else:
|
else:
|
||||||
raise ValueError(f"Unknown material type: {props.name}")
|
raise ValueError(f"Unknown material type: {props.name}")
|
||||||
|
|||||||
Reference in New Issue
Block a user