fix: swallowed exceptions
build and deploy Speckle functions / publish-automate-function-version (push) Has been cancelled

This commit is contained in:
Björn Steinhagen
2025-02-27 23:04:16 +01:00
parent 53fbfc0139
commit 98341cc99f
5 changed files with 107 additions and 49 deletions
+68 -35
View File
@@ -156,7 +156,7 @@ class RevitCarbonAnalyzer:
results = {
"processed_elements": [],
"skipped_elements": [],
"warning_elements": [], # For invalid elements
"warning_elements": [],
"errors": [],
"total_carbon": 0.0,
"missing_factors": {"timber": [], "steel": [], "concrete": []},
@@ -243,7 +243,19 @@ class RevitCarbonAnalyzer:
# Calculate carbon
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
embodied_carbon_data = {}
@@ -265,13 +277,13 @@ class RevitCarbonAnalyzer:
"value": result.database,
"units": None,
},
"ecf": {
"name": "ecf",
"embodiedCarbonFactor": {
"name": "embodiedCarbonFactor",
"value": result.factor,
"units": "kgCO₂e/m³",
},
"embodied carbon": {
"name": "embodied carbon",
"embodiedCarbon": {
"name": "embodiedCarbon",
"value": result.total_carbon,
"units": "kgCO₂e",
},
@@ -279,8 +291,8 @@ class RevitCarbonAnalyzer:
elif result.category == "Concrete":
# For concrete (include both concrete and reinforcement)
material_data = {
"volume": {
"name": "volume",
"concreteVolume": {
"name": "concreteVolume",
"value": result.concrete_volume,
"units": "",
},
@@ -289,38 +301,38 @@ class RevitCarbonAnalyzer:
"value": result.database,
"units": None,
},
"ecf": {
"name": "ecf",
"concreteEmbodiedCarbonFactor": {
"name": "concreteEmbodiedCarbonFactor",
"value": result.factor,
"units": "kgCO₂e/m³",
},
"concrete carbon": {
"name": "concrete carbon",
"concreteEmbodiedCarbon": {
"name": "concreteEmbodiedCarbon",
"value": result.concrete_carbon,
"units": "kgCO₂e",
},
"reinforcement mass": {
"name": "reinforcement mass",
"reinforcementMass": {
"name": "reinforcementMass",
"value": result.reinforcement_mass,
"units": "kg",
},
"reinforcement rate": {
"name": "reinforcement rate",
"reinforcementRate": {
"name": "reinforcementRate",
"value": result.reinforcement_rate,
"units": "kg/m³",
},
"reinforcement ecf": {
"name": "reinforcement ecf",
"reinforcementEmbodiedCarbonFactor": {
"name": "reinforcementEmbodiedCarbonFactor",
"value": result.reinforcement_factor,
"units": "kgCO₂e/kg",
},
"reinforcement carbon": {
"name": "reinforcement carbon",
"reinforcementEmbodiedCarbon": {
"name": "reinforcementEmbodiedCarbon",
"value": result.reinforcement_carbon,
"units": "kgCO₂e",
},
"embodied carbon": {
"name": "embodied carbon",
"embodiedCarbon": {
"name": "embodiedCarbon",
"value": result.total_carbon,
"units": "kgCO₂e",
},
@@ -338,13 +350,13 @@ class RevitCarbonAnalyzer:
"value": result.database,
"units": None,
},
"ecf": {
"name": "ecf",
"embodiedCarbonFactor": {
"name": "embodiedCarbonFactor",
"value": result.factor,
"units": "kgCO₂e/kg",
},
"embodied carbon": {
"name": "embodied carbon",
"embodiedCarbon": {
"name": "embodiedCarbon",
"value": result.total_carbon,
"units": "kgCO₂e",
},
@@ -357,9 +369,9 @@ class RevitCarbonAnalyzer:
if hasattr(element, "properties"):
element.properties["Embodied Carbon Calculation"] = embodied_carbon_data
return {
element_result = {
"id": element_id,
"status": "processed",
"status": "processed" if not material_errors else "warning",
"level": processed_element.level,
"category": processed_element.category,
"materials": [
@@ -373,11 +385,21 @@ class RevitCarbonAnalyzer:
"carbon_results": carbon_results,
"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:
return {
"id": element_id,
"status": "error",
"error": f"Carbon calculation failed: {str(e)}",
"reason": f"Carbon calculation failed: {str(e)}",
}
@staticmethod
@@ -485,8 +507,8 @@ def automate_function(
element_id,
key,
"{:0.2f} {}".format(
value["embodied carbon"]["value"],
value["embodied carbon"]["units"],
value["embodiedCarbon"]["value"],
value["embodiedCarbon"]["units"],
),
]
)
@@ -550,9 +572,9 @@ def automate_function(
)
# Upload mutated model
# automate_context.create_new_version_in_project(
# model_root, f"{commit_root.branchName}_embodied_carbon"
# )
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)
@@ -574,10 +596,21 @@ def _process_automation_results(
"""Process results and attach them to the automation context."""
# Process each category and attach to objects
# Successes
# Successes with gradient metadata
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(
category="Carbon Analysis",
metadata={"gradient": True, "gradientValues": embodied_carbon_values},
object_ids=[e["id"] for e in results["processed_elements"]],
message="Carbon calculations completed successfully for these elements!",
)
+20 -2
View File
@@ -12,9 +12,27 @@ class MaterialAliasService:
"glue laminated timber",
"glued laminated timber",
"glulam beam",
"GL36h",
"GL36h(1)",
"GL24h",
"GL28h",
"GL30h",
"GL32h",
"GL36c",
"GL36c(1)",
"GL24c",
"GL28c",
"GL30c",
"GL32c",
"softwood",
],
"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"],
"oriented strand board": ["osb", "osb board"],
"glt/nlt/dlt": [
@@ -41,7 +59,7 @@ class MaterialAliasService:
"rebar": ["reinforcing bar", "reinforcement"],
"owsj": ["open web steel joist", "steel joist"],
"fasteners": ["bolts", "screws", "nails", "rivets"],
"metal deck": ["deck", "decking"],
"metal deck": ["deck", "decking", "metal - decking"],
}
self._concrete_aliases = {
+10 -7
View File
@@ -45,9 +45,12 @@ class CarbonCalculator:
self._missing_steel_factors = set()
self._missing_concrete_factors = set()
def calculate_carbon(self, element: BuildingElement) -> Dict[str, CarbonResult]:
"""Calculate carbon emissions for an element's materials."""
def calculate_carbon(
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 = {}
errors = []
for material in element.materials:
try:
@@ -77,11 +80,13 @@ class CarbonCalculator:
)
self._missing_concrete_factors.add(f"{strength}_{element_type}")
print(
f"Error calculating carbon for {material.properties.name}: {str(e)}"
# Store error with material name instead of just printing
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(
self, material: Material, element_category: Optional[ElementCategory] = None
@@ -102,8 +107,6 @@ class CarbonCalculator:
def _calculate_metal_carbon(self, material: Material) -> CarbonResult:
"""Calculate carbon emissions for metal."""
if not material.mass:
raise ValueError("Mass required for metal carbon calculation")
# Get factor from cache or registry
if material.grade not in self._steel_factors_cache:
+2 -2
View File
@@ -14,7 +14,7 @@ class ElementProcessor:
"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):
self.material_processor = material_processor
@@ -108,7 +108,7 @@ class ElementProcessor:
properties = getattr(element, "properties")
material_quantities = properties["Material Quantities"]
for material_data in material_quantities.values(): # Added .values()
for material_data in material_quantities.values():
try:
material = self.material_processor.process_material(material_data)
materials.append(material)
+7 -3
View File
@@ -35,9 +35,13 @@ class MaterialProcessor:
"""Process materials with structural assets."""
if "concrete" in props.name.lower():
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)
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)
else:
raise ValueError(f"Unknown high-grade material: {props.name}")
@@ -60,7 +64,7 @@ class MaterialProcessor:
mass=mass,
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)
else:
raise ValueError(f"Unknown material type: {props.name}")