Files
swift-hvac-toolbox/Sources/Routes/Models/HeatingBalancePoint.swift

190 lines
5.2 KiB
Swift

import CoreModels
public enum HeatingBalancePoint {
public static let description: String = """
Calculate the heating balance point.
"""
public enum Mode: String, CaseIterable, Codable, Equatable, Sendable, Hashable {
case economic
case thermal
}
public enum Request: Codable, Equatable, Sendable, Hashable {
case economic(Economic)
case thermal(Thermal)
public struct Economic: Codable, Equatable, Sendable, Hashable {
public let fuelType: FuelType
public let fuelCostPerUnit: Double
public let fuelAFUE: Double
public let costPerKW: Double
public init(
fuelType: HeatingBalancePoint.FuelType,
fuelCostPerUnit: Double,
fuelAFUE: Double,
costPerKW: Double
) {
self.fuelType = fuelType
self.fuelCostPerUnit = fuelCostPerUnit
self.fuelAFUE = fuelAFUE
self.costPerKW = costPerKW
}
}
public struct Thermal: Codable, Equatable, Sendable, Hashable {
public let systemSize: Double
public let capacityAt47: Double?
public let capacityAt17: Double?
public let heatingDesignTemperature: Double?
public let buildingHeatLoss: HeatingBalancePoint.HeatLoss
public let climateZone: ClimateZone?
public init(
systemSize: Double,
capacityAt47: Double? = nil,
capacityAt17: Double? = nil,
heatingDesignTemperature: Double? = nil,
buildingHeatLoss: HeatingBalancePoint.HeatLoss,
climateZone: ClimateZone? = nil
) {
self.systemSize = systemSize
self.capacityAt47 = capacityAt47
self.capacityAt17 = capacityAt17
self.heatingDesignTemperature = heatingDesignTemperature
self.buildingHeatLoss = buildingHeatLoss
self.climateZone = climateZone
}
}
}
public enum Response: Codable, Equatable, Sendable {
case economic(Economic)
case thermal(Thermal)
public struct Economic: Codable, Equatable, Sendable {
public let balancePointTemperature: Double
public let fuelCostPerMMBTU: Double
public let electricCostPerMMBTU: Double
public let copAtBalancePoint: Double
public let electricFuelRatio: Double
public init(
balancePointTemperature: Double,
fuelCostPerMMBTU: Double,
electricCostPerMMBTU: Double,
copAtBalancePoint: Double,
electricFuelRatio: Double
) {
self.balancePointTemperature = balancePointTemperature
self.fuelCostPerMMBTU = fuelCostPerMMBTU
self.electricCostPerMMBTU = electricCostPerMMBTU
self.copAtBalancePoint = copAtBalancePoint
self.electricFuelRatio = electricFuelRatio
}
}
public struct Thermal: Codable, Equatable, Sendable {
public let capacityAt47: Double
public let capacityAt17: Double
public let balancePointTemperature: Double
public let heatLoss: Double
public let heatLossMode: HeatLoss.Mode
public let heatingDesignTemperature: Double
public let warnings: [String]
public init(
capacityAt47: Double,
capacityAt17: Double,
balancePointTemperature: Double,
heatLoss: Double,
heatLossMode: HeatLoss.Mode,
heatingDesignTemperature: Double,
warnings: [String]
) {
self.capacityAt47 = capacityAt47
self.capacityAt17 = capacityAt17
self.balancePointTemperature = balancePointTemperature
self.heatLoss = heatLoss
self.heatLossMode = heatLossMode
self.heatingDesignTemperature = heatingDesignTemperature
self.warnings = warnings
}
}
}
public enum HeatLoss: Codable, Equatable, Sendable, Hashable {
public enum Mode: String, CaseIterable, Codable, Equatable, Sendable, Hashable {
case estimated
case known
}
case known(btu: Double)
case estimated(squareFeet: Double)
public var mode: Mode {
switch self {
case .known: return .known
case .estimated: return .estimated
}
}
}
public enum FuelType: String, CaseIterable, Codable, Equatable, Sendable, Hashable {
case naturalGas
case propane
case oil
public var label: String {
switch self {
case .propane, .oil: return "\(rawValue.capitalized)"
case .naturalGas: return "Natural Gas"
}
}
public var units: String {
switch self {
case .propane, .oil: return "gallons"
case .naturalGas: return "therm"
}
}
}
}
#if DEBUG
public extension HeatingBalancePoint.Response {
static func mock(mode: HeatingBalancePoint.Mode) -> Self {
switch mode {
case .economic:
return .economic(.init(
balancePointTemperature: -10.8,
fuelCostPerMMBTU: 27.6,
electricCostPerMMBTU: 38.1,
copAtBalancePoint: 2.24,
electricFuelRatio: 1.38
))
case .thermal:
return .thermal(.init(
capacityAt47: 24600,
capacityAt17: 15100,
balancePointTemperature: 38.5,
heatLoss: 49667,
heatLossMode: .known,
heatingDesignTemperature: 5,
warnings: [
"Design temperature is estimated based on climate zone."
]
))
}
}
}
#endif