diff --git a/main.py b/main.py index b1eeb20..b02d063 100644 --- a/main.py +++ b/main.py @@ -52,7 +52,12 @@ class RevitCarbonAnalyzer: material_processor=self.material_processor, logger=Logging() ) self.carbon_calculator = CarbonCalculator( - steel_database=steel_database, timber_database=timber_database + steel_database=steel_database.value + if isinstance(steel_database, SteelDatabase) + else steel_database, + timber_database=timber_database.value + if isinstance(timber_database, SteelDatabase) + else timber_database, ) def analyze_model(self, model_root) -> dict: @@ -101,7 +106,17 @@ class RevitCarbonAnalyzer: # Calculate carbon try: + print( + f"Processing element: {element_id}, category: {processed_element.category.value}" + ) + print( + f"Materials: {[m.properties.name for m in processed_element.materials]}" + ) carbon_results = self.carbon_calculator.calculate_carbon(processed_element) + print(f"Carbon results: {carbon_results}") + print( + f"Total carbon: {sum(r.total_carbon for r in carbon_results.values())}" + ) return { "id": element_id, "status": "processed", diff --git a/src/domain/carbon/emission_factor_registry.py b/src/domain/carbon/emission_factor_registry.py index 19b725c..b9ed0e9 100644 --- a/src/domain/carbon/emission_factor_registry.py +++ b/src/domain/carbon/emission_factor_registry.py @@ -47,20 +47,19 @@ class EmissionFactorRegistry: "glt", "nlt", "dlt", - "glue laminated timber", "nail laminated timber", "dowel laminated timber", ], } self._steel_aliases = { - "hot rolled": ["hot-rolled", "hot_rolled", "hotrolled"], - "hss": ["hollow structural section", "hollow section", "tube steel"], - "plate": ["steel plate", "flat plate"], + "hot rolled": ["hot-rolled", "hot_rolled", "hotrolled", "steel"], + "hss": ["hollow structural section", "hollow section", "tube"], + "plate": ["flat plate"], "rebar": ["reinforcing bar", "reinforcement"], "owsj": ["open web steel joist", "steel joist"], "fasteners": ["bolts", "screws", "nails", "rivets"], - "metal deck": ["steel deck", "decking"], + "metal deck": ["deck", "decking"], } self._concrete_aliases = { @@ -94,14 +93,16 @@ class EmissionFactorRegistry: @staticmethod def _normalize_material_name(name: str, aliases: Dict[str, list]) -> str: - """Normalize material name using centralized aliases""" + """Normalize material name using centralized aliases with substring matching""" name = name.lower() - # Check if name contains any alias - for standard_name, variations in aliases.items(): - if name == standard_name: + # Check standard names first + for standard_name in aliases.keys(): + if standard_name in name: return standard_name + # Then check aliases + for standard_name, variations in aliases.items(): for variation in variations: if variation in name: return standard_name @@ -126,6 +127,8 @@ class EmissionFactorRegistry: normalized_name = self._normalize_material_name( material_name, self._timber_aliases ) + print(f"Looking up '{material_name}' in {database}") + print(f"Normalized name: {normalized_name}") return db.get_factor(normalized_name) def get_steel_factor( @@ -145,6 +148,8 @@ class EmissionFactorRegistry: normalized_name = self._normalize_material_name( material_name, self._steel_aliases ) + print(f"Looking up '{material_name}' in {database}") + print(f"Normalized name: {normalized_name}") return db.get_factor(normalized_name) def get_concrete_factor( diff --git a/src/services/carbon_calculator.py b/src/services/carbon_calculator.py index eaeb1ab..38db35f 100644 --- a/src/services/carbon_calculator.py +++ b/src/services/carbon_calculator.py @@ -30,7 +30,11 @@ class CarbonCalculator: """Calculate carbon emissions for an element's materials.""" results = {} + print(f"Calculating carbon for {len(element.materials)} materials") for material in element.materials: + print(f" Material: {material.properties.name}, type: {material.type}") + print(f" Structural asset: {material.properties.structural_asset}") + print(f" Volume: {material.properties.volume}, Mass: {material.mass}") try: result = self._calculate_material_carbon(material) results[material.properties.name] = result @@ -44,6 +48,7 @@ class CarbonCalculator: def _calculate_material_carbon(self, material: Material) -> CarbonResult: """Calculate carbon emissions for a single material.""" + print(f"Calculating for material type: {material.type}") if material.type == MaterialType.METAL: return self._calculate_metal_carbon(material) elif material.type == MaterialType.WOOD: @@ -60,9 +65,11 @@ class CarbonCalculator: # Get factor from cache or registry if material.grade not in self._steel_factors_cache: + print(f"Metal: {material.grade} → {self._steel_database}") factor = self._registry.get_steel_factor( material.grade, self._steel_database ) + print(f"Factor found: {factor}") if not factor: raise ValueError( f"No emission factor found for metal grade: {material.grade}" @@ -82,9 +89,13 @@ class CarbonCalculator: # Get factor from cache or registry if structural_asset not in self._timber_factors_cache: + print( + f"Wood: {material.properties.structural_asset} → {self._timber_database}" + ) factor = self._registry.get_timber_factor( structural_asset, self._timber_database ) + print(f"Factor found: {factor}") if not factor: raise ValueError( f"No emission factor found for wood type: {structural_asset}" diff --git a/tests/test_registry.py b/tests/test_registry.py new file mode 100644 index 0000000..3d26fdb --- /dev/null +++ b/tests/test_registry.py @@ -0,0 +1,41 @@ +import pytest + +from src.domain.carbon.databases.enums import TimberDatabase, SteelDatabase +from src.domain.carbon.emission_factor_registry import EmissionFactorRegistry + + +class TestRegistry: + """Test suite for the EmissionFactorRegistry""" + + @pytest.fixture + def registry(self): + """Create and return a registry instance""" + return EmissionFactorRegistry() + + def test_timber_database_lookup(self, registry): + """Test direct lookup of timber factors""" + # Test each database + factor = registry.get_timber_factor( + "FE_CLT Floor Panel (1)", TimberDatabase.Athena2021.value + ) + assert factor is not None + assert factor.value == 69 + + factor = registry.get_timber_factor( + "FE_Glulam", TimberDatabase.Binderholz2019.value + ) + assert factor is not None + assert factor.value == 118 + + def test_steel_database_lookup(self, registry): + """Test direct lookup of steel factors""" + factor = registry.get_steel_factor( + "Metal - Steel CSA G40", SteelDatabase.Type350MPa.value + ) + assert factor is not None + assert factor.value == 1.22 + + def test_invalid_database(self, registry): + """Test error handling for invalid database""" + with pytest.raises(ValueError, match="Unknown timber database"): + registry.get_timber_factor("CLT", "NonExistentDatabase")