93 lines
3.2 KiB
Swift
93 lines
3.2 KiB
Swift
import Dependencies
|
|
import Foundation
|
|
import Logging
|
|
import PsychrometricClient
|
|
import Routes
|
|
|
|
public extension HVACSystemPerformance.Request {
|
|
|
|
// TODO: Check if we should use psychrometrics for the request conditions instead
|
|
private static let airDensity = 0.075 // lb/ft^3 at standard conditions.
|
|
private static let specificHeat = 0.24 // BTU/lb at standard conditions (imperial).
|
|
|
|
func respond(logger: Logger) async throws -> HVACSystemPerformance.Response {
|
|
@Dependency(\.psychrometricClient) var psychrometricClient
|
|
|
|
try validate()
|
|
|
|
let altitude = parseAltitude()
|
|
let temperatureSplit = returnAirTemperature - supplyAirTemperature
|
|
|
|
let returnAirProperties = try await psychrometricClient.psychrometricProperties(.dryBulb(
|
|
.init(.init(returnAirTemperature)),
|
|
relativeHumidity: returnAirHumidity%,
|
|
altitude: altitude
|
|
))
|
|
|
|
let supplyAirProperties = try await psychrometricClient.psychrometricProperties(.dryBulb(
|
|
.init(.init(supplyAirTemperature)),
|
|
relativeHumidity: supplyAirHumidity%,
|
|
altitude: altitude
|
|
))
|
|
|
|
let airMassFlow = airflow * 60 * Self.airDensity
|
|
logger.debug("Air mass flow: \(airMassFlow)")
|
|
let condensationRate = airMassFlow * (
|
|
returnAirProperties.humidityRatio.value - supplyAirProperties.humidityRatio.value
|
|
) // lb/hr
|
|
let sensibleCapacity = airMassFlow * Self.specificHeat * temperatureSplit
|
|
logger.debug("Return enthalpy: \(returnAirProperties.enthalpy.value)")
|
|
logger.debug("Supply enthalpy: \(supplyAirProperties.enthalpy.value)")
|
|
let deltaEnthalpy = returnAirProperties.enthalpy.value - supplyAirProperties.enthalpy.value
|
|
logger.debug("Delta enthalpy: \(deltaEnthalpy)")
|
|
let totalCapacity = airMassFlow * deltaEnthalpy
|
|
|
|
let capacity = HVACSystemPerformance.Capacity(
|
|
total: totalCapacity,
|
|
sensible: sensibleCapacity,
|
|
latent: totalCapacity - sensibleCapacity
|
|
)
|
|
|
|
let systemMetrics = HVACSystemPerformance.SystemMetrics(
|
|
cfmPerTon: airflow / systemSize,
|
|
targetTemperatureSplit: (systemSize * 12000 * 0.75) / (1.08 * airflow),
|
|
actualTemperatureSplit: temperatureSplit,
|
|
condensationRatePoundsPerHour: condensationRate
|
|
)
|
|
|
|
return .init(
|
|
returnAirProperties: returnAirProperties,
|
|
supplyAirProperties: supplyAirProperties,
|
|
capacity: capacity,
|
|
systemMetrics: systemMetrics
|
|
)
|
|
}
|
|
|
|
private func parseAltitude() -> Length {
|
|
guard let altitude, altitude > 0 else { return .seaLevel }
|
|
return .init(altitude)
|
|
}
|
|
|
|
private func validate() throws {
|
|
guard returnAirTemperature > 0 else {
|
|
throw ValidationError(message: "Return air temperature should be greater than 0.")
|
|
}
|
|
guard returnAirHumidity > 0 else {
|
|
throw ValidationError(message: "Return air humidity should be greater than 0.")
|
|
}
|
|
guard supplyAirTemperature > 0 else {
|
|
throw ValidationError(message: "Supply air temperature should be greater than 0.")
|
|
}
|
|
guard supplyAirHumidity > 0 else {
|
|
throw ValidationError(message: "Supply air humidity should be greater than 0.")
|
|
}
|
|
guard systemSize > 0 else {
|
|
throw ValidationError(message: "System size should be greater than 0.")
|
|
}
|
|
}
|
|
|
|
struct ValidationError: Error {
|
|
let message: String
|
|
}
|
|
}
|