Spaces:
Sleeping
Sleeping
| """ | |
| Reference Data Module for HVAC Load Calculator | |
| This module provides reference data for materials, locations, and other parameters | |
| needed for HVAC load calculations. | |
| """ | |
| import pandas as pd | |
| import json | |
| from pathlib import Path | |
| class ReferenceData: | |
| """ | |
| A class to manage reference data for HVAC load calculations. | |
| """ | |
| def __init__(self): | |
| """Initialize the reference data.""" | |
| self.materials = self._load_materials() | |
| self.locations = self._load_locations() | |
| self.glass_types = self._load_glass_types() | |
| self.shading_factors = self._load_shading_factors() | |
| self.internal_loads = self._load_internal_loads() | |
| self.occupancy_factors = self._load_occupancy_factors() | |
| def _load_materials(self): | |
| """ | |
| Load building material properties. | |
| Returns: | |
| dict: Dictionary of material properties | |
| """ | |
| # This would typically load from a JSON or CSV file | |
| # For now, we'll define it directly | |
| materials = { | |
| "walls": { | |
| "brick_veneer": { | |
| "name": "Brick veneer with insulation", | |
| "u_value": 0.5, # W/m²°C | |
| "r_value": 2.0, # m²°C/W | |
| "description": "Brick veneer with timber frame and insulation" | |
| }, | |
| "double_brick": { | |
| "name": "Double brick", | |
| "u_value": 1.88, # W/m²°C | |
| "r_value": 0.53, # m²°C/W | |
| "description": "Double brick wall without insulation" | |
| }, | |
| "double_brick_insulated": { | |
| "name": "Double brick with insulation", | |
| "u_value": 0.6, # W/m²°C | |
| "r_value": 1.67, # m²°C/W | |
| "description": "Double brick wall with insulation" | |
| }, | |
| "timber_frame": { | |
| "name": "Timber frame", | |
| "u_value": 0.8, # W/m²°C | |
| "r_value": 1.25, # m²°C/W | |
| "description": "Timber frame wall with insulation" | |
| }, | |
| "concrete_block": { | |
| "name": "Concrete block", | |
| "u_value": 2.3, # W/m²°C | |
| "r_value": 0.43, # m²°C/W | |
| "description": "Concrete block wall without insulation" | |
| }, | |
| "concrete_block_insulated": { | |
| "name": "Concrete block with insulation", | |
| "u_value": 0.7, # W/m²°C | |
| "r_value": 1.43, # m²°C/W | |
| "description": "Concrete block wall with insulation" | |
| } | |
| }, | |
| "roofs": { | |
| "metal_deck_insulated": { | |
| "name": "Metal deck with insulation", | |
| "u_value": 0.46, # W/m²°C | |
| "r_value": 2.17, # m²°C/W | |
| "description": "Metal deck roof with insulation and plasterboard ceiling" | |
| }, | |
| "metal_deck_uninsulated": { | |
| "name": "Metal deck without insulation", | |
| "u_value": 2.2, # W/m²°C | |
| "r_value": 0.45, # m²°C/W | |
| "description": "Metal deck roof without insulation" | |
| }, | |
| "concrete_slab_roof": { | |
| "name": "Concrete slab roof", | |
| "u_value": 3.1, # W/m²°C | |
| "r_value": 0.32, # m²°C/W | |
| "description": "Concrete slab roof without insulation" | |
| }, | |
| "concrete_slab_insulated": { | |
| "name": "Concrete slab roof with insulation", | |
| "u_value": 0.5, # W/m²°C | |
| "r_value": 2.0, # m²°C/W | |
| "description": "Concrete slab roof with insulation" | |
| }, | |
| "tiled_roof_insulated": { | |
| "name": "Tiled roof with insulation", | |
| "u_value": 0.4, # W/m²°C | |
| "r_value": 2.5, # m²°C/W | |
| "description": "Tiled roof with insulation and plasterboard ceiling" | |
| }, | |
| "tiled_roof_uninsulated": { | |
| "name": "Tiled roof without insulation", | |
| "u_value": 2.0, # W/m²°C | |
| "r_value": 0.5, # m²°C/W | |
| "description": "Tiled roof without insulation" | |
| } | |
| }, | |
| "floors": { | |
| "concrete_slab_ground": { | |
| "name": "Concrete slab on ground", | |
| "u_value": 0.6, # W/m²°C | |
| "r_value": 1.67, # m²°C/W | |
| "description": "Concrete slab directly on ground" | |
| }, | |
| "concrete_slab_insulated": { | |
| "name": "Concrete slab with insulation", | |
| "u_value": 0.3, # W/m²°C | |
| "r_value": 3.33, # m²°C/W | |
| "description": "Concrete slab with insulation" | |
| }, | |
| "suspended_timber": { | |
| "name": "Suspended timber floor", | |
| "u_value": 1.5, # W/m²°C | |
| "r_value": 0.67, # m²°C/W | |
| "description": "Suspended timber floor without insulation" | |
| }, | |
| "suspended_timber_insulated": { | |
| "name": "Suspended timber floor with insulation", | |
| "u_value": 0.4, # W/m²°C | |
| "r_value": 2.5, # m²°C/W | |
| "description": "Suspended timber floor with insulation" | |
| } | |
| } | |
| } | |
| return materials | |
| def _load_locations(self): | |
| """ | |
| Load climate data for different locations. | |
| Returns: | |
| dict: Dictionary of location climate data | |
| """ | |
| # This would typically load from a JSON or CSV file | |
| # For now, we'll define it directly | |
| locations = { | |
| "sydney": { | |
| "name": "Sydney", | |
| "state": "NSW", | |
| "summer_design_temp": 32.0, # °C | |
| "winter_design_temp": 7.0, # °C | |
| "daily_temp_range": "medium", # 8.5-14°C | |
| "heating_degree_days": 740, # Base 18°C | |
| "cooling_degree_days": 350, # Base 18°C | |
| "latitude": -33.87, | |
| "longitude": 151.21 | |
| }, | |
| "melbourne": { | |
| "name": "Melbourne", | |
| "state": "VIC", | |
| "summer_design_temp": 35.0, # °C | |
| "winter_design_temp": 4.0, # °C | |
| "daily_temp_range": "medium", # 8.5-14°C | |
| "heating_degree_days": 1400, # Base 18°C | |
| "cooling_degree_days": 200, # Base 18°C | |
| "latitude": -37.81, | |
| "longitude": 144.96 | |
| }, | |
| "brisbane": { | |
| "name": "Brisbane", | |
| "state": "QLD", | |
| "summer_design_temp": 32.0, # °C | |
| "winter_design_temp": 9.0, # °C | |
| "daily_temp_range": "medium", # 8.5-14°C | |
| "heating_degree_days": 320, # Base 18°C | |
| "cooling_degree_days": 750, # Base 18°C | |
| "latitude": -27.47, | |
| "longitude": 153.03 | |
| }, | |
| "perth": { | |
| "name": "Perth", | |
| "state": "WA", | |
| "summer_design_temp": 37.0, # °C | |
| "winter_design_temp": 7.0, # °C | |
| "daily_temp_range": "high", # >14°C | |
| "heating_degree_days": 760, # Base 18°C | |
| "cooling_degree_days": 600, # Base 18°C | |
| "latitude": -31.95, | |
| "longitude": 115.86 | |
| }, | |
| "adelaide": { | |
| "name": "Adelaide", | |
| "state": "SA", | |
| "summer_design_temp": 38.0, # °C | |
| "winter_design_temp": 5.0, # °C | |
| "daily_temp_range": "high", # >14°C | |
| "heating_degree_days": 1100, # Base 18°C | |
| "cooling_degree_days": 500, # Base 18°C | |
| "latitude": -34.93, | |
| "longitude": 138.60 | |
| }, | |
| "hobart": { | |
| "name": "Hobart", | |
| "state": "TAS", | |
| "summer_design_temp": 28.0, # °C | |
| "winter_design_temp": 2.0, # °C | |
| "daily_temp_range": "medium", # 8.5-14°C | |
| "heating_degree_days": 1800, # Base 18°C | |
| "cooling_degree_days": 50, # Base 18°C | |
| "latitude": -42.88, | |
| "longitude": 147.33 | |
| }, | |
| "darwin": { | |
| "name": "Darwin", | |
| "state": "NT", | |
| "summer_design_temp": 34.0, # °C | |
| "winter_design_temp": 15.0, # °C | |
| "daily_temp_range": "low", # <8.5°C | |
| "heating_degree_days": 0, # Base 18°C | |
| "cooling_degree_days": 3500, # Base 18°C | |
| "latitude": -12.46, | |
| "longitude": 130.84 | |
| }, | |
| "canberra": { | |
| "name": "Canberra", | |
| "state": "ACT", | |
| "summer_design_temp": 35.0, # °C | |
| "winter_design_temp": -1.0, # °C | |
| "daily_temp_range": "high", # >14°C | |
| "heating_degree_days": 2000, # Base 18°C | |
| "cooling_degree_days": 150, # Base 18°C | |
| "latitude": -35.28, | |
| "longitude": 149.13 | |
| }, | |
| "mildura": { | |
| "name": "Mildura", | |
| "state": "VIC", | |
| "summer_design_temp": 38.0, # °C | |
| "winter_design_temp": 4.5, # °C | |
| "daily_temp_range": "high", # >14°C | |
| "heating_degree_days": 1200, # Base 18°C | |
| "cooling_degree_days": 700, # Base 18°C | |
| "latitude": -34.21, | |
| "longitude": 142.14 | |
| } | |
| } | |
| return locations | |
| def _load_glass_types(self): | |
| """ | |
| Load glass type properties. | |
| Returns: | |
| dict: Dictionary of glass type properties | |
| """ | |
| # This would typically load from a JSON or CSV file | |
| # For now, we'll define it directly | |
| glass_types = { | |
| "single": { | |
| "name": "Single glazing", | |
| "u_value": 5.8, # W/m²°C | |
| "shgc": 0.85, # Solar Heat Gain Coefficient | |
| "description": "Standard single glazed window" | |
| }, | |
| "double": { | |
| "name": "Double glazing", | |
| "u_value": 2.9, # W/m²°C | |
| "shgc": 0.75, # Solar Heat Gain Coefficient | |
| "description": "Standard double glazed window" | |
| }, | |
| "low_e": { | |
| "name": "Low-E double glazing", | |
| "u_value": 1.8, # W/m²°C | |
| "shgc": 0.65, # Solar Heat Gain Coefficient | |
| "description": "Double glazed window with low-emissivity coating" | |
| }, | |
| "triple": { | |
| "name": "Triple glazing", | |
| "u_value": 1.2, # W/m²°C | |
| "shgc": 0.6, # Solar Heat Gain Coefficient | |
| "description": "Triple glazed window" | |
| }, | |
| "tinted": { | |
| "name": "Tinted single glazing", | |
| "u_value": 5.8, # W/m²°C | |
| "shgc": 0.65, # Solar Heat Gain Coefficient | |
| "description": "Single glazed window with tinting" | |
| }, | |
| "tinted_double": { | |
| "name": "Tinted double glazing", | |
| "u_value": 2.9, # W/m²°C | |
| "shgc": 0.55, # Solar Heat Gain Coefficient | |
| "description": "Double glazed window with tinting" | |
| } | |
| } | |
| return glass_types | |
| def _load_shading_factors(self): | |
| """ | |
| Load shading factors for different shading devices. | |
| Returns: | |
| dict: Dictionary of shading factors | |
| """ | |
| # This would typically load from a JSON or CSV file | |
| # For now, we'll define it directly | |
| shading_factors = { | |
| "none": { | |
| "name": "No shading", | |
| "factor": 0.0, | |
| "description": "No shading devices" | |
| }, | |
| "internal_blinds": { | |
| "name": "Internal venetian blinds", | |
| "factor": 0.4, | |
| "description": "Internal venetian blinds" | |
| }, | |
| "internal_drapes": { | |
| "name": "Internal drapes", | |
| "factor": 0.3, | |
| "description": "Internal drapes or curtains" | |
| }, | |
| "external_awning": { | |
| "name": "External awning", | |
| "factor": 0.7, | |
| "description": "External awning" | |
| }, | |
| "external_shutters": { | |
| "name": "External shutters", | |
| "factor": 0.8, | |
| "description": "External shutters" | |
| }, | |
| "eaves": { | |
| "name": "Eaves or overhang", | |
| "factor": 0.5, | |
| "description": "Eaves or overhang" | |
| }, | |
| "pergola": { | |
| "name": "Pergola with vegetation", | |
| "factor": 0.6, | |
| "description": "Pergola with vegetation" | |
| } | |
| } | |
| return shading_factors | |
| def _load_internal_loads(self): | |
| """ | |
| Load internal load data. | |
| Returns: | |
| dict: Dictionary of internal load data | |
| """ | |
| # This would typically load from a JSON or CSV file | |
| # For now, we'll define it directly | |
| internal_loads = { | |
| "people": { | |
| "seated_resting": { | |
| "name": "Seated, resting", | |
| "sensible_heat": 75, # W per person | |
| "latent_heat": 30 # W per person | |
| }, | |
| "seated_light_work": { | |
| "name": "Seated, light work", | |
| "sensible_heat": 85, # W per person | |
| "latent_heat": 40 # W per person | |
| }, | |
| "standing_light_work": { | |
| "name": "Standing, light work", | |
| "sensible_heat": 90, # W per person | |
| "latent_heat": 50 # W per person | |
| }, | |
| "light_activity": { | |
| "name": "Light activity", | |
| "sensible_heat": 100, # W per person | |
| "latent_heat": 60 # W per person | |
| }, | |
| "medium_activity": { | |
| "name": "Medium activity", | |
| "sensible_heat": 120, # W per person | |
| "latent_heat": 80 # W per person | |
| } | |
| }, | |
| "lighting": { | |
| "incandescent": { | |
| "name": "Incandescent", | |
| "heat_factor": 1.0 # 100% of wattage becomes heat | |
| }, | |
| "fluorescent": { | |
| "name": "Fluorescent", | |
| "heat_factor": 1.2 # 120% of wattage becomes heat (includes ballast) | |
| }, | |
| "led": { | |
| "name": "LED", | |
| "heat_factor": 0.8 # 80% of wattage becomes heat | |
| } | |
| }, | |
| "appliances": { | |
| "kitchen": { | |
| "name": "Kitchen", | |
| "heat_gain": 1000 # W | |
| }, | |
| "living_room": { | |
| "name": "Living room", | |
| "heat_gain": 300 # W | |
| }, | |
| "bedroom": { | |
| "name": "Bedroom", | |
| "heat_gain": 150 # W | |
| }, | |
| "office": { | |
| "name": "Home office", | |
| "heat_gain": 450 # W | |
| } | |
| } | |
| } | |
| return internal_loads | |
| def _load_occupancy_factors(self): | |
| """ | |
| Load occupancy correction factors. | |
| Returns: | |
| dict: Dictionary of occupancy correction factors | |
| """ | |
| # This would typically load from a JSON or CSV file | |
| # For now, we'll define it directly | |
| occupancy_factors = { | |
| "continuous": { | |
| "name": "Continuous", | |
| "factor": 1.0, | |
| "description": "Continuously heated" | |
| }, | |
| "intermittent": { | |
| "name": "Intermittent", | |
| "factor": 0.8, | |
| "description": "Heated during occupied hours" | |
| }, | |
| "night_setback": { | |
| "name": "Night setback", | |
| "factor": 0.9, | |
| "description": "Temperature setback at night" | |
| }, | |
| "weekend_off": { | |
| "name": "Weekend off", | |
| "factor": 0.85, | |
| "description": "Heating off during weekends" | |
| }, | |
| "vacation_home": { | |
| "name": "Vacation home", | |
| "factor": 0.6, | |
| "description": "Occasionally occupied" | |
| } | |
| } | |
| return occupancy_factors | |
| def get_material_by_type(self, material_type, material_id): | |
| """ | |
| Get material properties by type and ID. | |
| Args: | |
| material_type (str): Type of material ('walls', 'roofs', 'floors') | |
| material_id (str): ID of the material | |
| Returns: | |
| dict: Material properties | |
| """ | |
| # Check if this is a custom material (custom_[type]) | |
| if material_id == f"custom_{material_type}": | |
| # Return the custom material from session state if available | |
| import streamlit as st | |
| if "custom_materials" in st.session_state and material_type in st.session_state.custom_materials: | |
| return st.session_state.custom_materials[material_type] | |
| # Return a default custom material template if not in session state | |
| return { | |
| "name": f"Custom {material_type[:-1]}", # Remove 's' from end | |
| "u_value": 1.0, # Default U-value | |
| "r_value": 1.0, # Default R-value | |
| "description": f"Custom {material_type[:-1]} with user-defined properties" | |
| } | |
| # Return predefined material | |
| if material_type in self.materials and material_id in self.materials[material_type]: | |
| return self.materials[material_type][material_id] | |
| return None | |
| def get_location_data(self, location_id): | |
| """ | |
| Get climate data for a location. | |
| Args: | |
| location_id (str): ID of the location | |
| Returns: | |
| dict: Location climate data | |
| """ | |
| if location_id in self.locations: | |
| return self.locations[location_id] | |
| return None | |
| def get_glass_type(self, glass_id): | |
| """ | |
| Get glass type properties. | |
| Args: | |
| glass_id (str): ID of the glass type | |
| Returns: | |
| dict: Glass type properties | |
| """ | |
| if glass_id in self.glass_types: | |
| return self.glass_types[glass_id] | |
| return None | |
| def get_shading_factor(self, shading_id): | |
| """ | |
| Get shading factor. | |
| Args: | |
| shading_id (str): ID of the shading type | |
| Returns: | |
| dict: Shading factor data | |
| """ | |
| if shading_id in self.shading_factors: | |
| return self.shading_factors[shading_id] | |
| return None | |
| def get_internal_load(self, load_type, load_id): | |
| """ | |
| Get internal load data. | |
| Args: | |
| load_type (str): Type of internal load ('people', 'lighting', 'appliances') | |
| load_id (str): ID of the internal load | |
| Returns: | |
| dict: Internal load data | |
| """ | |
| if load_type in self.internal_loads and load_id in self.internal_loads[load_type]: | |
| return self.internal_loads[load_type][load_id] | |
| return None | |
| def get_occupancy_factor(self, occupancy_id): | |
| """ | |
| Get occupancy correction factor. | |
| Args: | |
| occupancy_id (str): ID of the occupancy type | |
| Returns: | |
| dict: Occupancy correction factor data | |
| """ | |
| if occupancy_id in self.occupancy_factors: | |
| return self.occupancy_factors[occupancy_id] | |
| return None | |
| def export_to_json(self, output_dir): | |
| """ | |
| Export all reference data to JSON files. | |
| Args: | |
| output_dir (str): Directory to save JSON files | |
| Returns: | |
| bool: True if successful, False otherwise | |
| """ | |
| try: | |
| output_path = Path(output_dir) | |
| output_path.mkdir(parents=True, exist_ok=True) | |
| # Export materials | |
| with open(output_path / "materials.json", "w") as f: | |
| json.dump(self.materials, f, indent=2) | |
| # Export locations | |
| with open(output_path / "locations.json", "w") as f: | |
| json.dump(self.locations, f, indent=2) | |
| # Export glass types | |
| with open(output_path / "glass_types.json", "w") as f: | |
| json.dump(self.glass_types, f, indent=2) | |
| # Export shading factors | |
| with open(output_path / "shading_factors.json", "w") as f: | |
| json.dump(self.shading_factors, f, indent=2) | |
| # Export internal loads | |
| with open(output_path / "internal_loads.json", "w") as f: | |
| json.dump(self.internal_loads, f, indent=2) | |
| # Export occupancy factors | |
| with open(output_path / "occupancy_factors.json", "w") as f: | |
| json.dump(self.occupancy_factors, f, indent=2) | |
| return True | |
| except Exception as e: | |
| print(f"Error exporting reference data: {e}") | |
| return False | |
| # Example usage | |
| if __name__ == "__main__": | |
| ref_data = ReferenceData() | |
| # Example: Get wall material properties | |
| brick_veneer = ref_data.get_material_by_type("walls", "brick_veneer") | |
| print("Brick Veneer Wall Properties:", brick_veneer) | |
| # Example: Get location climate data | |
| sydney_data = ref_data.get_location_data("sydney") | |
| print("Sydney Climate Data:", sydney_data) | |
| # Example: Export all data to JSON | |
| ref_data.export_to_json("reference_data") | |