import Dependencies import PsychrometricClient public enum HVACSystemPerformance { public static let description = """ Analyze HVAC system performance and capacity. """ public struct Request: Codable, Equatable, Sendable { public let altitude: Double? public let airflow: Double public let returnAirTemperature: Double public let returnAirHumidity: Double public let supplyAirTemperature: Double public let supplyAirHumidity: Double public let systemSize: Double public init( altitude: Double? = nil, airflow: Double, returnAirTemperature: Double, returnAirHumidity: Double, supplyAirTemperature: Double, supplyAirHumidity: Double, systemSize: Double ) { self.altitude = altitude self.airflow = airflow self.returnAirTemperature = returnAirTemperature self.returnAirHumidity = returnAirHumidity self.supplyAirTemperature = supplyAirTemperature self.supplyAirHumidity = supplyAirHumidity self.systemSize = systemSize } } public struct Response: Codable, Equatable, Sendable { public let returnAirProperties: PsychrometricProperties public let supplyAirProperties: PsychrometricProperties public let capacity: Capacity public let systemMetrics: SystemMetrics public init( returnAirProperties: PsychrometricProperties, supplyAirProperties: PsychrometricProperties, capacity: HVACSystemPerformance.Capacity, systemMetrics: HVACSystemPerformance.SystemMetrics ) { self.returnAirProperties = returnAirProperties self.supplyAirProperties = supplyAirProperties self.capacity = capacity self.systemMetrics = systemMetrics } } // TODO: Add delta-enthalpy. public struct Capacity: Codable, Equatable, Sendable { public let total: Double public let sensible: Double public let latent: Double public var shr: Double { sensible / total } public init(total: Double, sensible: Double, latent: Double) { self.total = total self.sensible = sensible self.latent = latent } } public struct SystemMetrics: Codable, Equatable, Sendable { public let cfmPerTon: Double public let targetTemperatureSplit: Double public let actualTemperatureSplit: Double public let condensationRatePoundsPerHour: Double // lb/hr public let condensationRateGallonsPerHour: Double // gal/hr public init( cfmPerTon: Double, targetTemperatureSplit: Double, actualTemperatureSplit: Double, condensationRatePoundsPerHour: Double ) { self.cfmPerTon = cfmPerTon self.targetTemperatureSplit = targetTemperatureSplit self.actualTemperatureSplit = actualTemperatureSplit self.condensationRatePoundsPerHour = condensationRatePoundsPerHour self.condensationRateGallonsPerHour = condensationRatePoundsPerHour * 0.12 } } } #if DEBUG public extension HVACSystemPerformance.Response { static func mock() async throws -> Self { @Dependency(\.psychrometricClient) var psychrometricClient return try await .init( returnAirProperties: psychrometricClient.psychrometricProperties(.dryBulb(75, relativeHumidity: 50%)), supplyAirProperties: psychrometricClient.psychrometricProperties(.dryBulb(55, relativeHumidity: 87%)), capacity: .mock, systemMetrics: .mock ) } } public extension HVACSystemPerformance.Capacity { static var mock: Self { .init(total: 24000, sensible: 19000, latent: 5000) } } public extension HVACSystemPerformance.SystemMetrics { static let mock = Self( cfmPerTon: 400, targetTemperatureSplit: 20.8, actualTemperatureSplit: 18.7, condensationRatePoundsPerHour: 16981.3 ) } #endif