""" Reference data structures for HVAC Load Calculator. This module contains reference data for materials, construction types, and other HVAC-related data. """ from typing import Dict, List, Any, Optional import pandas as pd import json import os import logging from uuid import uuid4 # Configure logging logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) # Define paths DATA_DIR = os.path.dirname(os.path.abspath(__file__)) DEFAULT_DATA_FILE = os.path.join(DATA_DIR, "reference_data.json") class ReferenceData: """Class for managing reference data for the HVAC calculator.""" def __init__(self): """Initialize reference data structures.""" self.materials = {} self.wall_types = {} self.roof_types = {} self.floor_types = {} self.window_types = {} self.door_types = {} self.internal_loads = {} try: self._load_all_data() except Exception as e: logger.error(f"Error initializing reference data: {str(e)}") raise def _load_all_data(self) -> None: """Load all reference data, attempting to load from JSON first.""" try: if os.path.exists(DEFAULT_DATA_FILE): self._load_from_json(DEFAULT_DATA_FILE) else: self._load_default_data() self.export_to_json(DEFAULT_DATA_FILE) except Exception as e: logger.error(f"Error loading reference data: {str(e)}") self._load_default_data() # Fallback to default data def _load_default_data(self) -> None: """Load default reference data.""" self.materials = self._load_materials() self.wall_types = self._load_wall_types() self.roof_types = self._load_roof_types() self.floor_types = self._load_floor_types() self.window_types = self._load_window_types() self.door_types = self._load_door_types() self.internal_loads = self._load_internal_loads() def _load_materials(self) -> Dict[str, Dict[str, Any]]: """ Load material properties. Returns: Dictionary of material properties """ return { "brick": { "id": str(uuid4()), "name": "Common Brick", "conductivity": 0.72, # W/(m·K) "density": 1920, # kg/m³ "specific_heat": 840, # J/(kg·K) "typical_thickness": 0.1, # m "emissivity": 0.9, "solar_absorptance": 0.7 }, "concrete": { "id": str(uuid4()), "name": "Concrete", "conductivity": 1.4, # W/(m·K) "density": 2300, # kg/m³ "specific_heat": 880, # J/(kg·K) "typical_thickness": 0.2, # m "emissivity": 0.92, "solar_absorptance": 0.65 }, "mineral_wool": { "id": str(uuid4()), "name": "Mineral Wool Insulation", "conductivity": 0.04, # W/(m·K) "density": 30, # kg/m³ "specific_heat": 840, # J/(kg·K) "typical_thickness": 0.1, # m "emissivity": 0.9, "solar_absorptance": 0.6 }, # Additional materials "polyurethane_foam": { "id": str(uuid4()), "name": "Polyurethane Foam", "conductivity": 0.025, # W/(m·K) "density": 40, # kg/m³ "specific_heat": 1500, # J/(kg·K) "typical_thickness": 0.05, # m "emissivity": 0.9, "solar_absorptance": 0.6 }, "fiberglass_insulation": { "id": str(uuid4()), "name": "Fiberglass Insulation", "conductivity": 0.045, # W/(m·K) "density": 12, # kg/m³ "specific_heat": 850, # J/(kg·K) "typical_thickness": 0.15, # m "emissivity": 0.9, "solar_absorptance": 0.6 }, "stucco": { "id": str(uuid4()), "name": "Stucco", "conductivity": 0.7, # W/(m·K) "density": 1850, # kg/m³ "specific_heat": 900, # J/(kg·K) "typical_thickness": 0.025, # m "emissivity": 0.92, "solar_absorptance": 0.5 } # Add more materials as needed } def _load_wall_types(self) -> Dict[str, Dict[str, Any]]: """ Load predefined wall types. Returns: Dictionary of wall types with properties """ return { "brick_veneer_wood_frame": { "id": str(uuid4()), "name": "Brick Veneer with Wood Frame", "description": "Brick veneer with wood frame, insulation, and gypsum board", "u_value": 0.35, # W/(m²·K) "wall_group": "B", "layers": [ {"material": "brick", "thickness": 0.1}, {"material": "air_gap", "thickness": 0.025}, {"material": "wood", "thickness": 0.038}, {"material": "mineral_wool", "thickness": 0.089}, {"material": "gypsum_board", "thickness": 0.0125} ], "thermal_mass": 180, # kg/m² "color": "Medium" }, "insulated_concrete_form": { "id": str(uuid4()), "name": "Insulated Concrete Form", "description": "ICF with EPS insulation and concrete core", "u_value": 0.25, # W/(m²·K) "wall_group": "C", "layers": [ {"material": "eps_insulation", "thickness": 0.05}, {"material": "concrete", "thickness": 0.15}, {"material": "eps_insulation", "thickness": 0.05}, {"material": "gypsum_board", "thickness": 0.0125} ], "thermal_mass": 220, # kg/m² "color": "Light" }, # Additional wall types "sip_panel": { "id": str(uuid4()), "name": "Structural Insulated Panel", "description": "SIP with OSB and EPS core", "u_value": 0.28, # W/(m²·K) "wall_group": "A", "layers": [ {"material": "wood", "thickness": 0.012}, {"material": "eps_insulation", "thickness": 0.15}, {"material": "wood", "thickness": 0.012}, {"material": "gypsum_board", "thickness": 0.0125} ], "thermal_mass": 80, # kg/m² "color": "Light" } } def _load_roof_types(self) -> Dict[str, Dict[str, Any]]: """ Load predefined roof types. Returns: Dictionary of roof types with properties """ return { "flat_roof_concrete": { "id": str(uuid4()), "name": "Flat Concrete Roof with Insulation", "description": "Flat concrete roof with insulation and ceiling", "u_value": 0.25, # W/(m²·K) "roof_group": "B", "layers": [ {"material": "concrete", "thickness": 0.15}, {"material": "eps_insulation", "thickness": 0.15}, {"material": "gypsum_board", "thickness": 0.0125} ], "solar_absorptance": 0.7, "emissivity": 0.9 }, "green_roof": { "id": str(uuid4()), "name": "Green Roof", "description": "Vegetated roof with insulation and drainage", "u_value": 0.22, # W/(m²·K) "roof_group": "A", "layers": [ {"material": "soil", "thickness": 0.1}, {"material": "eps_insulation", "thickness": 0.1}, {"material": "concrete", "thickness": 0.1}, {"material": "gypsum_board", "thickness": 0.0125} ], "solar_absorptance": 0.5, "emissivity": 0.95 } } def _load_floor_types(self) -> Dict[str, Dict[str, Any]]: """ Load predefined floor types. Returns: Dictionary of floor types with properties """ return { "concrete_slab_on_grade": { "id": str(uuid4()), "name": "Concrete Slab on Grade", "description": "Concrete slab on grade with insulation", "u_value": 0.3, # W/(m²·K) "is_ground_contact": True, "layers": [ {"material": "concrete", "thickness": 0.1}, {"material": "eps_insulation", "thickness": 0.05} ], "thermal_mass": 230 # kg/m² }, "radiant_floor": { "id": str(uuid4()), "name": "Radiant Floor", "description": "Concrete floor with radiant heating and insulation", "u_value": 0.27, # W/(m²·K) "is_ground_contact": True, "layers": [ {"material": "tile", "thickness": 0.015}, {"material": "concrete", "thickness": 0.1}, {"material": "eps_insulation", "thickness": 0.075} ], "thermal_mass": 240 # kg/m² } } def _load_window_types(self) -> Dict[str, Dict[str, Any]]: """ Load predefined window types. Returns: Dictionary of window types with properties """ return { "double_glazed_argon_low_e": { "id": str(uuid4()), "name": "Double Glazed with Argon and Low-E", "description": "Double glazed window with argon fill, low-e coating, and vinyl frame", "u_value": 1.4, # W/(m²·K) "shgc": 0.4, "vt": 0.7, "glazing_layers": 2, "gas_fill": "Argon", "frame_type": "Vinyl", "low_e_coating": True, "frame_factor": 0.15 }, "electrochromic_window": { "id": str(uuid4()), "name": "Electrochromic Window", "description": "Smart window with dynamic tinting", "u_value": 1.2, # W/(m²·K) "shgc": 0.35, "vt": 0.65, "glazing_layers": 2, "gas_fill": "Argon", "frame_type": "Fiberglass", "low_e_coating": True, "frame_factor": 0.12 } } def _load_door_types(self) -> Dict[str, Dict[str, Any]]: """ Load predefined door types. Returns: Dictionary of door types with properties """ return { "insulated_steel_door": { "id": str(uuid4()), "name": "Insulated Steel Door", "description": "Insulated steel door with no glazing", "u_value": 1.2, # W/(m²·K) "glazing_percentage": 0, "door_type": "Solid", "thermal_mass": 50 # kg/m² }, "insulated_fiberglass_door": { "id": str(uuid4()), "name": "Insulated Fiberglass Door", "description": "Insulated fiberglass door with small glazing", "u_value": 1.5, # W/(m²·K) "glazing_percentage": 10, "door_type": "Partially glazed", "shgc": 0.7, "vt": 0.8, "thermal_mass": 40 # kg/m² } } def _load_internal_loads(self) -> Dict[str, Dict[str, Any]]: """ Load internal load data. Returns: Dictionary of internal load types with properties """ return { "occupancy": { "office_typing": { "id": str(uuid4()), "name": "Office Typing", "sensible_heat": 75, # W per person "latent_heat": 55, # W per person "metabolic_rate": 1.2 # met }, "retail_sales": { "id": str(uuid4()), "name": "Retail Sales", "sensible_heat": 80, # W per person "latent_heat": 70, # W per person "metabolic_rate": 1.4 # met } }, "lighting": { "led_high_efficiency": { "id": str(uuid4()), "name": "High Efficiency LED", "power_density_range": [4, 8], # W/m² "heat_to_space": 0.85, "efficacy": 120 # lm/W } }, "equipment": { "computer_workstation": { "id": str(uuid4()), "name": "Computer Workstation", "power_density_range": [15, 25], # W/m² "sensible_fraction": 0.95, "latent_fraction": 0.05 } } } def _load_from_json(self, file_path: str) -> None: """ Load reference data from JSON file. Args: file_path: Path to JSON file """ try: with open(file_path, 'r') as f: data = json.load(f) self.materials = data.get("materials", self.materials) self.wall_types = data.get("wall_types", self.wall_types) self.roof_types = data.get("roof_types", self.roof_types) self.floor_types = data.get("floor_types", self.floor_types) self.window_types = data.get("window_types", self.window_types) self.door_types = data.get("door_types", self.door_types) self.internal_loads = data.get("internal_loads", self.internal_loads) logger.info(f"Successfully loaded reference data from {file_path}") except Exception as e: logger.error(f"Error loading JSON data from {file_path}: {str(e)}") raise def export_to_json(self, file_path: str) -> None: """ Export all reference data to a JSON file. Args: file_path: Path to the output JSON file """ try: data = { "materials": self.materials, "wall_types": self.wall_types, "roof_types": self.roof_types, "floor_types": self.floor_types, "window_types": self.window_types, "door_types": self.door_types, "internal_loads": self.internal_loads } with open(file_path, 'w') as f: json.dump(data, f, indent=4) logger.info(f"Successfully exported reference data to {file_path}") except Exception as e: logger.error(f"Error exporting to JSON: {str(e)}") raise # Getter methods with validation def get_material(self, material_id: str) -> Optional[Dict[str, Any]]: return self.materials.get(material_id) def get_wall_type(self, wall_type_id: str) -> Optional[Dict[str, Any]]: return self.wall_types.get(wall_type_id) def get_roof_type(self, roof_type_id: str) -> Optional[Dict[str, Any]]: return self.roof_types.get(roof_type_id) def get_floor_type(self, floor_type_id: str) -> Optional[Dict[str, Any]]: return self.floor_types.get(floor_type_id) def get_window_type(self, window_type_id: str) -> Optional[Dict[str, Any]]: return self.window_types.get(window_type_id) def get_door_type(self, door_type_id: str) -> Optional[Dict[str, Any]]: return self.door_types.get(door_type_id) def get_internal_load(self, load_type: str, load_id: str) -> Optional[Dict[str, Any]]: return self.internal_loads.get(load_type, {}).get(load_id) # Singleton instance try: reference_data = ReferenceData() except Exception as e: logger.error(f"Failed to create ReferenceData instance: {str(e)}") raise if __name__ == "__main__": try: reference_data.export_to_json(DEFAULT_DATA_FILE) except Exception as e: logger.error(f"Error exporting default data: {str(e)}")