mabuseif/HVAC
0
1"""2Calculation Method Interface for HVAC Load Calculator3 4This module defines the interface for calculation methods in the HVAC Load Calculator.5It provides a base class that all calculation methods should inherit from.6"""7 8from abc import ABC, abstractmethod9 10 11class CalculationMethod(ABC):12 """13 Abstract base class for HVAC load calculation methods.14 15 All calculation methods should inherit from this class and implement16 the required methods.17 """18 19 @property20 @abstractmethod21 def name(self):22 """23 Get the name of the calculation method.24 25 Returns:26 str: Name of the calculation method27 """28 pass29 30 @property31 @abstractmethod32 def description(self):33 """34 Get the description of the calculation method.35 36 Returns:37 str: Description of the calculation method38 """39 pass40 41 @property42 @abstractmethod43 def version(self):44 """45 Get the version of the calculation method.46 47 Returns:48 str: Version of the calculation method49 """50 pass51 52 @abstractmethod53 def calculate(self, input_data):54 """55 Perform the calculation.56 57 Args:58 input_data (dict): Input data for the calculation59 60 Returns:61 dict: Calculation results62 """63 pass64 65 @abstractmethod66 def get_input_schema(self):67 """68 Get the input schema for the calculation method.69 70 Returns:71 dict: JSON schema for input validation72 """73 pass74 75 @abstractmethod76 def get_output_schema(self):77 """78 Get the output schema for the calculation method.79 80 Returns:81 dict: JSON schema for output validation82 """83 pass84 85 86class ASHRAECoolingMethod(CalculationMethod):87 """88 ASHRAE method for cooling load calculation.89 """90 91 @property92 def name(self):93 return "ASHRAE Cooling Load Method"94 95 @property96 def description(self):97 return "Calculates cooling loads using the ASHRAE method for residential buildings."98 99 @property100 def version(self):101 return "1.0"102 103 def calculate(self, input_data):104 """105 Calculate cooling load using the ASHRAE method.106 107 Args:108 input_data (dict): Input data for the calculation109 110 Returns:111 dict: Calculation results112 """113 from cooling_load import CoolingLoadCalculator114 115 calculator = CoolingLoadCalculator()116 117 # Extract input data118 building_components = input_data.get('building_components', [])119 windows = input_data.get('windows', [])120 infiltration = input_data.get('infiltration', {})121 internal_gains = input_data.get('internal_gains', {})122 123 # Perform calculation124 results = calculator.calculate_total_cooling_load(125 building_components=building_components,126 windows=windows,127 infiltration=infiltration,128 internal_gains=internal_gains129 )130 131 return results132 133 def get_input_schema(self):134 """135 Get the input schema for the ASHRAE cooling load method.136 137 Returns:138 dict: JSON schema for input validation139 """140 return {141 "type": "object",142 "properties": {143 "building_components": {144 "type": "array",145 "items": {146 "type": "object",147 "properties": {148 "name": {"type": "string"},149 "area": {"type": "number", "minimum": 0},150 "u_value": {"type": "number", "minimum": 0},151 "temp_diff": {"type": "number"}152 },153 "required": ["area", "u_value", "temp_diff"]154 }155 },156 "windows": {157 "type": "array",158 "items": {159 "type": "object",160 "properties": {161 "name": {"type": "string"},162 "area": {"type": "number", "minimum": 0},163 "u_value": {"type": "number", "minimum": 0},164 "orientation": {"type": "string", "enum": ["north", "east", "south", "west", "horizontal"]},165 "glass_type": {"type": "string"},166 "shading": {"type": "string"},167 "shade_factor": {"type": "number", "minimum": 0, "maximum": 1},168 "temp_diff": {"type": "number"}169 },170 "required": ["area", "u_value", "orientation", "temp_diff"]171 }172 },173 "infiltration": {174 "type": "object",175 "properties": {176 "volume": {"type": "number", "minimum": 0},177 "air_changes": {"type": "number", "minimum": 0},178 "temp_diff": {"type": "number"}179 },180 "required": ["volume", "air_changes", "temp_diff"]181 },182 "internal_gains": {183 "type": "object",184 "properties": {185 "num_people": {"type": "integer", "minimum": 0},186 "has_kitchen": {"type": "boolean"},187 "equipment_watts": {"type": "number", "minimum": 0}188 },189 "required": ["num_people"]190 }191 },192 "required": ["building_components", "infiltration", "internal_gains"]193 }194 195 def get_output_schema(self):196 """197 Get the output schema for the ASHRAE cooling load method.198 199 Returns:200 dict: JSON schema for output validation201 """202 return {203 "type": "object",204 "properties": {205 "conduction_gain": {"type": "number"},206 "window_conduction_gain": {"type": "number"},207 "window_solar_gain": {"type": "number"},208 "infiltration_gain": {"type": "number"},209 "internal_gain": {"type": "number"},210 "sensible_load": {"type": "number"},211 "latent_load": {"type": "number"},212 "total_load": {"type": "number"}213 },214 "required": ["sensible_load", "latent_load", "total_load"]215 }216 217 218class ASHRAEHeatingMethod(CalculationMethod):219 """220 ASHRAE method for heating load calculation.221 """222 223 @property224 def name(self):225 return "ASHRAE Heating Load Method"226 227 @property228 def description(self):229 return "Calculates heating loads using the ASHRAE method for residential buildings."230 231 @property232 def version(self):233 return "1.0"234 235 def calculate(self, input_data):236 """237 Calculate heating load using the ASHRAE method.238 239 Args:240 input_data (dict): Input data for the calculation241 242 Returns:243 dict: Calculation results244 """245 from heating_load import HeatingLoadCalculator246 247 calculator = HeatingLoadCalculator()248 249 # Extract input data250 building_components = input_data.get('building_components', [])251 infiltration = input_data.get('infiltration', {})252 253 # Perform calculation254 results = calculator.calculate_total_heating_load(255 building_components=building_components,256 infiltration=infiltration257 )258 259 # Calculate annual heating requirement if location and occupancy data are provided260 if 'location' in input_data and 'occupancy_type' in input_data:261 location = input_data.get('location')262 occupancy_type = input_data.get('occupancy_type')263 base_temp = input_data.get('base_temp', 18)264 265 annual_results = calculator.calculate_annual_heating_requirement(266 results['total_load'],267 location,268 occupancy_type,269 base_temp270 )271 272 # Combine results273 results.update(annual_results)274 275 return results276 277 def get_input_schema(self):278 """279 Get the input schema for the ASHRAE heating load method.280 281 Returns:282 dict: JSON schema for input validation283 """284 return {285 "type": "object",286 "properties": {287 "building_components": {288 "type": "array",289 "items": {290 "type": "object",291 "properties": {292 "name": {"type": "string"},293 "area": {"type": "number", "minimum": 0},294 "u_value": {"type": "number", "minimum": 0},295 "temp_diff": {"type": "number", "minimum": 0}296 },297 "required": ["area", "u_value", "temp_diff"]298 }299 },300 "infiltration": {301 "type": "object",302 "properties": {303 "volume": {"type": "number", "minimum": 0},304 "air_changes": {"type": "number", "minimum": 0},305 "temp_diff": {"type": "number", "minimum": 0}306 },307 "required": ["volume", "air_changes", "temp_diff"]308 },309 "location": {"type": "string"},310 "occupancy_type": {"type": "string"},311 "base_temp": {"type": "number"}312 },313 "required": ["building_components", "infiltration"]314 }315 316 def get_output_schema(self):317 """318 Get the output schema for the ASHRAE heating load method.319 320 Returns:321 dict: JSON schema for output validation322 """323 return {324 "type": "object",325 "properties": {326 "component_losses": {327 "type": "object",328 "additionalProperties": {"type": "number"}329 },330 "total_conduction_loss": {"type": "number"},331 "infiltration_loss": {"type": "number"},332 "total_load": {"type": "number"},333 "heating_degree_days": {"type": "number"},334 "correction_factor": {"type": "number"},335 "annual_energy_kwh": {"type": "number"},336 "annual_energy_mj": {"type": "number"}337 },338 "required": ["total_load"]339 }340 341 342class CalculationMethodRegistry:343 """344 Registry for calculation methods.345 346 This class maintains a registry of available calculation methods347 and provides methods to access them.348 """349 350 def __init__(self):351 """Initialize the registry."""352 self._methods = {}353 354 def register_method(self, method_id, method_class):355 """356 Register a calculation method.357 358 Args:359 method_id (str): Unique identifier for the method360 method_class (type): Class implementing the CalculationMethod interface361 362 Returns:363 bool: True if registration was successful, False otherwise364 """365 if method_id in self._methods:366 return False367 368 if not issubclass(method_class, CalculationMethod):369 return False370 371 self._methods[method_id] = method_class372 return True373 374 def get_method(self, method_id):375 """376 Get a calculation method by ID.377 378 Args:379 method_id (str): Unique identifier for the method380 381 Returns:382 CalculationMethod: Instance of the calculation method, or None if not found383 """384 if method_id not in self._methods:385 return None386 387 return self._methods[method_id]()388 389 def get_available_methods(self):390 """391 Get a list of available calculation methods.392 393 Returns:394 list: List of dictionaries with method information395 """396 methods = []397 for method_id, method_class in self._methods.items():398 method = method_class()399 methods.append({400 'id': method_id,401 'name': method.name,402 'description': method.description,403 'version': method.version404 })405 406 return methods407 408 409# Create a global registry instance410registry = CalculationMethodRegistry()411 412# Register the built-in calculation methods413registry.register_method('ashrae_cooling', ASHRAECoolingMethod)414registry.register_method('ashrae_heating', ASHRAEHeatingMethod)415 416 417# Example of how to add a new calculation method418"""419class CustomCoolingMethod(CalculationMethod):420 @property421 def name(self):422 return "Custom Cooling Method"423 424 @property425 def description(self):426 return "A custom method for calculating cooling loads."427 428 @property429 def version(self):430 return "1.0"431 432 def calculate(self, input_data):433 # Custom calculation logic434 pass435 436 def get_input_schema(self):437 # Custom input schema438 pass439 440 def get_output_schema(self):441 # Custom output schema442 pass443 444# Register the custom method445registry.register_method('custom_cooling', CustomCoolingMethod)446"""447 