test: add tests for lookup
This commit is contained in:
@@ -52,7 +52,12 @@ class RevitCarbonAnalyzer:
|
|||||||
material_processor=self.material_processor, logger=Logging()
|
material_processor=self.material_processor, logger=Logging()
|
||||||
)
|
)
|
||||||
self.carbon_calculator = CarbonCalculator(
|
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:
|
def analyze_model(self, model_root) -> dict:
|
||||||
@@ -101,7 +106,17 @@ class RevitCarbonAnalyzer:
|
|||||||
|
|
||||||
# Calculate carbon
|
# Calculate carbon
|
||||||
try:
|
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)
|
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 {
|
return {
|
||||||
"id": element_id,
|
"id": element_id,
|
||||||
"status": "processed",
|
"status": "processed",
|
||||||
|
|||||||
@@ -47,20 +47,19 @@ class EmissionFactorRegistry:
|
|||||||
"glt",
|
"glt",
|
||||||
"nlt",
|
"nlt",
|
||||||
"dlt",
|
"dlt",
|
||||||
"glue laminated timber",
|
|
||||||
"nail laminated timber",
|
"nail laminated timber",
|
||||||
"dowel laminated timber",
|
"dowel laminated timber",
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|
||||||
self._steel_aliases = {
|
self._steel_aliases = {
|
||||||
"hot rolled": ["hot-rolled", "hot_rolled", "hotrolled"],
|
"hot rolled": ["hot-rolled", "hot_rolled", "hotrolled", "steel"],
|
||||||
"hss": ["hollow structural section", "hollow section", "tube steel"],
|
"hss": ["hollow structural section", "hollow section", "tube"],
|
||||||
"plate": ["steel plate", "flat plate"],
|
"plate": ["flat plate"],
|
||||||
"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": ["steel deck", "decking"],
|
"metal deck": ["deck", "decking"],
|
||||||
}
|
}
|
||||||
|
|
||||||
self._concrete_aliases = {
|
self._concrete_aliases = {
|
||||||
@@ -94,14 +93,16 @@ class EmissionFactorRegistry:
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _normalize_material_name(name: str, aliases: Dict[str, list]) -> str:
|
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()
|
name = name.lower()
|
||||||
|
|
||||||
# Check if name contains any alias
|
# Check standard names first
|
||||||
for standard_name, variations in aliases.items():
|
for standard_name in aliases.keys():
|
||||||
if name == standard_name:
|
if standard_name in name:
|
||||||
return standard_name
|
return standard_name
|
||||||
|
|
||||||
|
# Then check aliases
|
||||||
|
for standard_name, variations in aliases.items():
|
||||||
for variation in variations:
|
for variation in variations:
|
||||||
if variation in name:
|
if variation in name:
|
||||||
return standard_name
|
return standard_name
|
||||||
@@ -126,6 +127,8 @@ class EmissionFactorRegistry:
|
|||||||
normalized_name = self._normalize_material_name(
|
normalized_name = self._normalize_material_name(
|
||||||
material_name, self._timber_aliases
|
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)
|
return db.get_factor(normalized_name)
|
||||||
|
|
||||||
def get_steel_factor(
|
def get_steel_factor(
|
||||||
@@ -145,6 +148,8 @@ class EmissionFactorRegistry:
|
|||||||
normalized_name = self._normalize_material_name(
|
normalized_name = self._normalize_material_name(
|
||||||
material_name, self._steel_aliases
|
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)
|
return db.get_factor(normalized_name)
|
||||||
|
|
||||||
def get_concrete_factor(
|
def get_concrete_factor(
|
||||||
|
|||||||
@@ -30,7 +30,11 @@ class CarbonCalculator:
|
|||||||
"""Calculate carbon emissions for an element's materials."""
|
"""Calculate carbon emissions for an element's materials."""
|
||||||
results = {}
|
results = {}
|
||||||
|
|
||||||
|
print(f"Calculating carbon for {len(element.materials)} materials")
|
||||||
for material in element.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:
|
try:
|
||||||
result = self._calculate_material_carbon(material)
|
result = self._calculate_material_carbon(material)
|
||||||
results[material.properties.name] = result
|
results[material.properties.name] = result
|
||||||
@@ -44,6 +48,7 @@ class CarbonCalculator:
|
|||||||
|
|
||||||
def _calculate_material_carbon(self, material: Material) -> CarbonResult:
|
def _calculate_material_carbon(self, material: Material) -> CarbonResult:
|
||||||
"""Calculate carbon emissions for a single material."""
|
"""Calculate carbon emissions for a single material."""
|
||||||
|
print(f"Calculating for material type: {material.type}")
|
||||||
if material.type == MaterialType.METAL:
|
if material.type == MaterialType.METAL:
|
||||||
return self._calculate_metal_carbon(material)
|
return self._calculate_metal_carbon(material)
|
||||||
elif material.type == MaterialType.WOOD:
|
elif material.type == MaterialType.WOOD:
|
||||||
@@ -60,9 +65,11 @@ class CarbonCalculator:
|
|||||||
|
|
||||||
# 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:
|
||||||
|
print(f"Metal: {material.grade} → {self._steel_database}")
|
||||||
factor = self._registry.get_steel_factor(
|
factor = self._registry.get_steel_factor(
|
||||||
material.grade, self._steel_database
|
material.grade, self._steel_database
|
||||||
)
|
)
|
||||||
|
print(f"Factor found: {factor}")
|
||||||
if not factor:
|
if not factor:
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
f"No emission factor found for metal grade: {material.grade}"
|
f"No emission factor found for metal grade: {material.grade}"
|
||||||
@@ -82,9 +89,13 @@ class CarbonCalculator:
|
|||||||
|
|
||||||
# Get factor from cache or registry
|
# Get factor from cache or registry
|
||||||
if structural_asset not in self._timber_factors_cache:
|
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(
|
factor = self._registry.get_timber_factor(
|
||||||
structural_asset, self._timber_database
|
structural_asset, self._timber_database
|
||||||
)
|
)
|
||||||
|
print(f"Factor found: {factor}")
|
||||||
if not factor:
|
if not factor:
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
f"No emission factor found for wood type: {structural_asset}"
|
f"No emission factor found for wood type: {structural_asset}"
|
||||||
|
|||||||
@@ -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")
|
||||||
Reference in New Issue
Block a user