""" Calculation Method Interface for HVAC Load Calculator This module defines the interface for calculation methods in the HVAC Load Calculator. It provides a base class that all calculation methods should inherit from. """ from abc import ABC, abstractmethod class CalculationMethod(ABC): """ Abstract base class for HVAC load calculation methods. All calculation methods should inherit from this class and implement the required methods. """ @property @abstractmethod def name(self): """ Get the name of the calculation method. Returns: str: Name of the calculation method """ pass @property @abstractmethod def description(self): """ Get the description of the calculation method. Returns: str: Description of the calculation method """ pass @property @abstractmethod def version(self): """ Get the version of the calculation method. Returns: str: Version of the calculation method """ pass @abstractmethod def calculate(self, input_data): """ Perform the calculation. Args: input_data (dict): Input data for the calculation Returns: dict: Calculation results """ pass @abstractmethod def get_input_schema(self): """ Get the input schema for the calculation method. Returns: dict: JSON schema for input validation """ pass @abstractmethod def get_output_schema(self): """ Get the output schema for the calculation method. Returns: dict: JSON schema for output validation """ pass class ASHRAECoolingMethod(CalculationMethod): """ ASHRAE method for cooling load calculation. """ @property def name(self): return "ASHRAE Cooling Load Method" @property def description(self): return "Calculates cooling loads using the ASHRAE method for residential buildings." @property def version(self): return "1.0" def calculate(self, input_data): """ Calculate cooling load using the ASHRAE method. Args: input_data (dict): Input data for the calculation Returns: dict: Calculation results """ from cooling_load import CoolingLoadCalculator calculator = CoolingLoadCalculator() # Extract input data building_components = input_data.get('building_components', []) windows = input_data.get('windows', []) infiltration = input_data.get('infiltration', {}) internal_gains = input_data.get('internal_gains', {}) # Perform calculation results = calculator.calculate_total_cooling_load( building_components=building_components, windows=windows, infiltration=infiltration, internal_gains=internal_gains ) return results def get_input_schema(self): """ Get the input schema for the ASHRAE cooling load method. Returns: dict: JSON schema for input validation """ return { "type": "object", "properties": { "building_components": { "type": "array", "items": { "type": "object", "properties": { "name": {"type": "string"}, "area": {"type": "number", "minimum": 0}, "u_value": {"type": "number", "minimum": 0}, "temp_diff": {"type": "number"} }, "required": ["area", "u_value", "temp_diff"] } }, "windows": { "type": "array", "items": { "type": "object", "properties": { "name": {"type": "string"}, "area": {"type": "number", "minimum": 0}, "u_value": {"type": "number", "minimum": 0}, "orientation": {"type": "string", "enum": ["north", "east", "south", "west", "horizontal"]}, "glass_type": {"type": "string"}, "shading": {"type": "string"}, "shade_factor": {"type": "number", "minimum": 0, "maximum": 1}, "temp_diff": {"type": "number"} }, "required": ["area", "u_value", "orientation", "temp_diff"] } }, "infiltration": { "type": "object", "properties": { "volume": {"type": "number", "minimum": 0}, "air_changes": {"type": "number", "minimum": 0}, "temp_diff": {"type": "number"} }, "required": ["volume", "air_changes", "temp_diff"] }, "internal_gains": { "type": "object", "properties": { "num_people": {"type": "integer", "minimum": 0}, "has_kitchen": {"type": "boolean"}, "equipment_watts": {"type": "number", "minimum": 0} }, "required": ["num_people"] } }, "required": ["building_components", "infiltration", "internal_gains"] } def get_output_schema(self): """ Get the output schema for the ASHRAE cooling load method. Returns: dict: JSON schema for output validation """ return { "type": "object", "properties": { "conduction_gain": {"type": "number"}, "window_conduction_gain": {"type": "number"}, "window_solar_gain": {"type": "number"}, "infiltration_gain": {"type": "number"}, "internal_gain": {"type": "number"}, "sensible_load": {"type": "number"}, "latent_load": {"type": "number"}, "total_load": {"type": "number"} }, "required": ["sensible_load", "latent_load", "total_load"] } class ASHRAEHeatingMethod(CalculationMethod): """ ASHRAE method for heating load calculation. """ @property def name(self): return "ASHRAE Heating Load Method" @property def description(self): return "Calculates heating loads using the ASHRAE method for residential buildings." @property def version(self): return "1.0" def calculate(self, input_data): """ Calculate heating load using the ASHRAE method. Args: input_data (dict): Input data for the calculation Returns: dict: Calculation results """ from heating_load import HeatingLoadCalculator calculator = HeatingLoadCalculator() # Extract input data building_components = input_data.get('building_components', []) infiltration = input_data.get('infiltration', {}) # Perform calculation results = calculator.calculate_total_heating_load( building_components=building_components, infiltration=infiltration ) # Calculate annual heating requirement if location and occupancy data are provided if 'location' in input_data and 'occupancy_type' in input_data: location = input_data.get('location') occupancy_type = input_data.get('occupancy_type') base_temp = input_data.get('base_temp', 18) annual_results = calculator.calculate_annual_heating_requirement( results['total_load'], location, occupancy_type, base_temp ) # Combine results results.update(annual_results) return results def get_input_schema(self): """ Get the input schema for the ASHRAE heating load method. Returns: dict: JSON schema for input validation """ return { "type": "object", "properties": { "building_components": { "type": "array", "items": { "type": "object", "properties": { "name": {"type": "string"}, "area": {"type": "number", "minimum": 0}, "u_value": {"type": "number", "minimum": 0}, "temp_diff": {"type": "number", "minimum": 0} }, "required": ["area", "u_value", "temp_diff"] } }, "infiltration": { "type": "object", "properties": { "volume": {"type": "number", "minimum": 0}, "air_changes": {"type": "number", "minimum": 0}, "temp_diff": {"type": "number", "minimum": 0} }, "required": ["volume", "air_changes", "temp_diff"] }, "location": {"type": "string"}, "occupancy_type": {"type": "string"}, "base_temp": {"type": "number"} }, "required": ["building_components", "infiltration"] } def get_output_schema(self): """ Get the output schema for the ASHRAE heating load method. Returns: dict: JSON schema for output validation """ return { "type": "object", "properties": { "component_losses": { "type": "object", "additionalProperties": {"type": "number"} }, "total_conduction_loss": {"type": "number"}, "infiltration_loss": {"type": "number"}, "total_load": {"type": "number"}, "heating_degree_days": {"type": "number"}, "correction_factor": {"type": "number"}, "annual_energy_kwh": {"type": "number"}, "annual_energy_mj": {"type": "number"} }, "required": ["total_load"] } class CalculationMethodRegistry: """ Registry for calculation methods. This class maintains a registry of available calculation methods and provides methods to access them. """ def __init__(self): """Initialize the registry.""" self._methods = {} def register_method(self, method_id, method_class): """ Register a calculation method. Args: method_id (str): Unique identifier for the method method_class (type): Class implementing the CalculationMethod interface Returns: bool: True if registration was successful, False otherwise """ if method_id in self._methods: return False if not issubclass(method_class, CalculationMethod): return False self._methods[method_id] = method_class return True def get_method(self, method_id): """ Get a calculation method by ID. Args: method_id (str): Unique identifier for the method Returns: CalculationMethod: Instance of the calculation method, or None if not found """ if method_id not in self._methods: return None return self._methods[method_id]() def get_available_methods(self): """ Get a list of available calculation methods. Returns: list: List of dictionaries with method information """ methods = [] for method_id, method_class in self._methods.items(): method = method_class() methods.append({ 'id': method_id, 'name': method.name, 'description': method.description, 'version': method.version }) return methods # Create a global registry instance registry = CalculationMethodRegistry() # Register the built-in calculation methods registry.register_method('ashrae_cooling', ASHRAECoolingMethod) registry.register_method('ashrae_heating', ASHRAEHeatingMethod) # Example of how to add a new calculation method """ class CustomCoolingMethod(CalculationMethod): @property def name(self): return "Custom Cooling Method" @property def description(self): return "A custom method for calculating cooling loads." @property def version(self): return "1.0" def calculate(self, input_data): # Custom calculation logic pass def get_input_schema(self): # Custom input schema pass def get_output_schema(self): # Custom output schema pass # Register the custom method registry.register_method('custom_cooling', CustomCoolingMethod) """