feat: Adds heat pump heating interpolation.
All checks were successful
CI / Ubuntu (push) Successful in 11m46s
All checks were successful
CI / Ubuntu (push) Successful in 11m46s
This commit is contained in:
@@ -3,6 +3,7 @@ disabled_rules:
|
|||||||
- fuction_body_length
|
- fuction_body_length
|
||||||
- opening_brace
|
- opening_brace
|
||||||
- nesting
|
- nesting
|
||||||
|
- type_body_length
|
||||||
|
|
||||||
included:
|
included:
|
||||||
- Sources
|
- Sources
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ import Models
|
|||||||
import Validations
|
import Validations
|
||||||
|
|
||||||
extension HouseLoad: AsyncValidatable {
|
extension HouseLoad: AsyncValidatable {
|
||||||
|
|
||||||
public var body: some AsyncValidation<Self> {
|
public var body: some AsyncValidation<Self> {
|
||||||
AsyncValidator.accumulating {
|
AsyncValidator.accumulating {
|
||||||
AsyncValidator.greaterThan(\.coolingTotal, 0)
|
AsyncValidator.greaterThan(\.coolingTotal, 0)
|
||||||
|
|||||||
@@ -222,8 +222,8 @@ private extension CoolingInterpolation.OneWayOutdoor {
|
|||||||
|
|
||||||
private func interpolate(
|
private func interpolate(
|
||||||
outdoorDesignTemperature: Int,
|
outdoorDesignTemperature: Int,
|
||||||
aboveCapacity: KeyPath<CoolingInterpolation.OneWayOutdoor.Capacities.Capacity, Int>,
|
aboveCapacity: KeyPath<CoolingInterpolation.OneWayOutdoor.Capacities.CapacityContainer, Int>,
|
||||||
belowCapacity: KeyPath<CoolingInterpolation.OneWayOutdoor.Capacities.Capacity, Int>
|
belowCapacity: KeyPath<CoolingInterpolation.OneWayOutdoor.Capacities.CapacityContainer, Int>
|
||||||
) async -> Int {
|
) async -> Int {
|
||||||
return await interpolateOutdoorCapacity(
|
return await interpolateOutdoorCapacity(
|
||||||
outdoorDesignTemperature: outdoorDesignTemperature,
|
outdoorDesignTemperature: outdoorDesignTemperature,
|
||||||
@@ -357,7 +357,7 @@ extension CoolingInterpolation.OneWayOutdoor.Capacities: AsyncValidatable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension CoolingInterpolation.OneWayOutdoor.Capacities.Capacity: AsyncValidatable {
|
extension CoolingInterpolation.OneWayOutdoor.Capacities.CapacityContainer: AsyncValidatable {
|
||||||
public var body: some AsyncValidation<Self> {
|
public var body: some AsyncValidation<Self> {
|
||||||
AsyncValidator.accumulating {
|
AsyncValidator.accumulating {
|
||||||
AsyncValidator.greaterThan(\.outdoorTemperature, 0)
|
AsyncValidator.greaterThan(\.outdoorTemperature, 0)
|
||||||
|
|||||||
80
Sources/ManualS/Internal/HeatPumpHeatingInterpolation.swift
Normal file
80
Sources/ManualS/Internal/HeatPumpHeatingInterpolation.swift
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
import CoreFoundation
|
||||||
|
import Models
|
||||||
|
import Validations
|
||||||
|
|
||||||
|
extension HeatPumpHeatingInterpolation.Request {
|
||||||
|
|
||||||
|
func respond() async throws -> HeatPumpHeatingInterpolation.Response {
|
||||||
|
try await validate()
|
||||||
|
let altitudeAdjustmentMultiplier = try await altitudeAdjustmentMultiplier()
|
||||||
|
let finalCapacity = finalCapacity(altitudeAdjustmentMultiplier)
|
||||||
|
let balancePointTemperature = try await balancePoint(finalCapacity)
|
||||||
|
let capacityAtDesign = capacityAtDesign(finalCapacity)
|
||||||
|
let requiredKW = try await requiredKW(capacityAtDesign)
|
||||||
|
return .init(
|
||||||
|
altitudeAdjustmentMultiplier: altitudeAdjustmentMultiplier,
|
||||||
|
balancePointTemperature: balancePointTemperature,
|
||||||
|
capacityAtDesign: capacityAtDesign,
|
||||||
|
finalCapacity: finalCapacity,
|
||||||
|
supplementalHeatRequired: requiredKW
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private func balancePoint(_ finalCapacity: Capacity.HeatPumpHeating) async throws -> Int {
|
||||||
|
let response = try await BalancePoint.Request(
|
||||||
|
winterDesignTemperature: winterDesignTemperature,
|
||||||
|
heatLoss: heatLoss,
|
||||||
|
heatPumpCapacity: finalCapacity
|
||||||
|
).respond()
|
||||||
|
return Int(response.balancePointTemperature)
|
||||||
|
}
|
||||||
|
|
||||||
|
private func altitudeAdjustmentMultiplier() async throws -> Double? {
|
||||||
|
guard let elevation else { return nil }
|
||||||
|
|
||||||
|
let response = try await Derating.Request(
|
||||||
|
elevation: elevation,
|
||||||
|
systemType: .airToAir(type: .heatPump, compressor: .singleSpeed, climate: climateType)
|
||||||
|
).respond()
|
||||||
|
|
||||||
|
return response.heating
|
||||||
|
}
|
||||||
|
|
||||||
|
private func finalCapacity(
|
||||||
|
_ adjustmentMultiplier: Double?
|
||||||
|
) -> Capacity.HeatPumpHeating {
|
||||||
|
guard let adjustmentMultiplier else { return capacity }
|
||||||
|
return .init(
|
||||||
|
at47: Int(Double(capacity.at47) * adjustmentMultiplier),
|
||||||
|
at17: Int(Double(capacity.at17) * adjustmentMultiplier)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private func capacityAtDesign(
|
||||||
|
_ finalCapacity: Capacity.HeatPumpHeating
|
||||||
|
) -> Int {
|
||||||
|
let outdoorTemperature = Double(winterDesignTemperature)
|
||||||
|
let derating = Double((finalCapacity.at47 - finalCapacity.at17) / 30)
|
||||||
|
* (17 - outdoorTemperature)
|
||||||
|
return Int(Double(finalCapacity.at17) - derating)
|
||||||
|
}
|
||||||
|
|
||||||
|
private func requiredKW(_ capacityAtDesign: Int) async throws -> Int {
|
||||||
|
let response = try await RequiredKW.Request(
|
||||||
|
capacityAtDesign: capacityAtDesign,
|
||||||
|
heatLoss: heatLoss
|
||||||
|
).respond()
|
||||||
|
return Int(response.requiredKW)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
extension HeatPumpHeatingInterpolation.Request: AsyncValidatable {
|
||||||
|
|
||||||
|
public var body: some AsyncValidation<Self> {
|
||||||
|
AsyncValidator.accumulating {
|
||||||
|
AsyncValidator.greaterThan(\.heatLoss, 0)
|
||||||
|
AsyncValidator.validate(\.capacity)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -13,7 +13,11 @@ public extension DependencyValues {
|
|||||||
public struct ManualS: Sendable {
|
public struct ManualS: Sendable {
|
||||||
public var balancePoint: @Sendable (BalancePoint.Request) async throws -> BalancePoint.Response
|
public var balancePoint: @Sendable (BalancePoint.Request) async throws -> BalancePoint.Response
|
||||||
public var derating: @Sendable (Derating.Request) async throws -> Derating.Response
|
public var derating: @Sendable (Derating.Request) async throws -> Derating.Response
|
||||||
public var coolingInterpolation: @Sendable (CoolingInterpolation.Request) async throws -> CoolingInterpolation.Response
|
public var coolingInterpolation:
|
||||||
|
@Sendable (CoolingInterpolation.Request) async throws -> CoolingInterpolation.Response
|
||||||
|
public var heatPumpHeatingInterpolation:
|
||||||
|
@Sendable (HeatPumpHeatingInterpolation.Request) async throws -> HeatPumpHeatingInterpolation.Response
|
||||||
|
|
||||||
public var requiredKW: @Sendable (RequiredKW.Request) async throws -> RequiredKW.Response
|
public var requiredKW: @Sendable (RequiredKW.Request) async throws -> RequiredKW.Response
|
||||||
public var sizingLimits: @Sendable (SizingLimits.Request) async throws -> SizingLimits.Response
|
public var sizingLimits: @Sendable (SizingLimits.Request) async throws -> SizingLimits.Response
|
||||||
}
|
}
|
||||||
@@ -23,6 +27,7 @@ extension ManualS: DependencyKey {
|
|||||||
balancePoint: { try await $0.respond() },
|
balancePoint: { try await $0.respond() },
|
||||||
derating: { try await $0.respond() },
|
derating: { try await $0.respond() },
|
||||||
coolingInterpolation: { try await $0.respond() },
|
coolingInterpolation: { try await $0.respond() },
|
||||||
|
heatPumpHeatingInterpolation: { try await $0.respond() },
|
||||||
requiredKW: { try await $0.respond() },
|
requiredKW: { try await $0.respond() },
|
||||||
sizingLimits: { try await $0.respond() }
|
sizingLimits: { try await $0.respond() }
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ public enum CoolingInterpolation {
|
|||||||
|
|
||||||
public let elevation: Int?
|
public let elevation: Int?
|
||||||
public let summerDesignInfo: DesignInfo.Summer
|
public let summerDesignInfo: DesignInfo.Summer
|
||||||
public let coolingLoad: Models.Capacity.Cooling
|
public let coolingLoad: Capacity.Cooling
|
||||||
public let systemType: SystemType
|
public let systemType: SystemType
|
||||||
public let interpolation: InterpolationRequest
|
public let interpolation: InterpolationRequest
|
||||||
|
|
||||||
@@ -27,18 +27,18 @@ public enum CoolingInterpolation {
|
|||||||
|
|
||||||
public let failed: Bool
|
public let failed: Bool
|
||||||
public let failures: [String]?
|
public let failures: [String]?
|
||||||
public let interpolatedCapacity: Models.Capacity.Cooling
|
public let interpolatedCapacity: Capacity.Cooling
|
||||||
public let excessLatent: Int
|
public let excessLatent: Int
|
||||||
public let finalCapacityAtDesign: Models.Capacity.Cooling
|
public let finalCapacityAtDesign: Capacity.Cooling
|
||||||
public let altitudeDerating: AdjustmentMultiplier?
|
public let altitudeDerating: AdjustmentMultiplier?
|
||||||
public let capacityAsPercentOfLoad: Models.Capacity.Cooling
|
public let capacityAsPercentOfLoad: Capacity.Cooling
|
||||||
public let sizingLimits: SizingLimits.Response
|
public let sizingLimits: SizingLimits.Response
|
||||||
|
|
||||||
public init(
|
public init(
|
||||||
failures: [String]? = nil,
|
failures: [String]? = nil,
|
||||||
interpolatedCapacity: Models.Capacity.Cooling,
|
interpolatedCapacity: Capacity.Cooling,
|
||||||
excessLatent: Int,
|
excessLatent: Int,
|
||||||
finalCapacityAtDesign: Models.Capacity.Cooling,
|
finalCapacityAtDesign: Capacity.Cooling,
|
||||||
altitudeDerating: AdjustmentMultiplier? = nil,
|
altitudeDerating: AdjustmentMultiplier? = nil,
|
||||||
capacityAsPercentOfLoad: Capacity.Cooling,
|
capacityAsPercentOfLoad: Capacity.Cooling,
|
||||||
sizingLimits: SizingLimits.Response
|
sizingLimits: SizingLimits.Response
|
||||||
@@ -55,7 +55,7 @@ public enum CoolingInterpolation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public enum InterpolationRequest: Codable, Equatable, Sendable {
|
public enum InterpolationRequest: Codable, Equatable, Sendable {
|
||||||
case noInterpolation(Models.Capacity.ManufacturersCooling, AdjustmentMultiplier? = nil)
|
case noInterpolation(Capacity.ManufacturersCooling, AdjustmentMultiplier? = nil)
|
||||||
case oneWayIndoor(OneWayIndoor)
|
case oneWayIndoor(OneWayIndoor)
|
||||||
case oneWayOutdoor(OneWayOutdoor)
|
case oneWayOutdoor(OneWayOutdoor)
|
||||||
case twoWay(TwoWay)
|
case twoWay(TwoWay)
|
||||||
@@ -82,12 +82,12 @@ public enum CoolingInterpolation {
|
|||||||
|
|
||||||
public struct Capacities: Codable, Equatable, Sendable {
|
public struct Capacities: Codable, Equatable, Sendable {
|
||||||
|
|
||||||
public let aboveDewpoint: Models.Capacity.ManufacturersContainer
|
public let aboveDewpoint: Capacity.ManufacturersContainer
|
||||||
public let belowDewpoint: Models.Capacity.ManufacturersContainer
|
public let belowDewpoint: Capacity.ManufacturersContainer
|
||||||
|
|
||||||
public init(
|
public init(
|
||||||
aboveDewpoint: Models.Capacity.ManufacturersContainer,
|
aboveDewpoint: Capacity.ManufacturersContainer,
|
||||||
belowDewpoint: Models.Capacity.ManufacturersContainer
|
belowDewpoint: Capacity.ManufacturersContainer
|
||||||
) {
|
) {
|
||||||
self.aboveDewpoint = aboveDewpoint
|
self.aboveDewpoint = aboveDewpoint
|
||||||
self.belowDewpoint = belowDewpoint
|
self.belowDewpoint = belowDewpoint
|
||||||
@@ -116,18 +116,18 @@ public enum CoolingInterpolation {
|
|||||||
|
|
||||||
public struct Capacities: Codable, Equatable, Sendable {
|
public struct Capacities: Codable, Equatable, Sendable {
|
||||||
|
|
||||||
public let aboveOutdoor: Capacity
|
public let aboveOutdoor: CapacityContainer
|
||||||
public let belowOutdoor: Capacity
|
public let belowOutdoor: CapacityContainer
|
||||||
|
|
||||||
public init(
|
public init(
|
||||||
aboveOutdoor: CoolingInterpolation.OneWayOutdoor.Capacities.Capacity,
|
aboveOutdoor: CoolingInterpolation.OneWayOutdoor.Capacities.CapacityContainer,
|
||||||
belowOutdoor: CoolingInterpolation.OneWayOutdoor.Capacities.Capacity
|
belowOutdoor: CoolingInterpolation.OneWayOutdoor.Capacities.CapacityContainer
|
||||||
) {
|
) {
|
||||||
self.aboveOutdoor = aboveOutdoor
|
self.aboveOutdoor = aboveOutdoor
|
||||||
self.belowOutdoor = belowOutdoor
|
self.belowOutdoor = belowOutdoor
|
||||||
}
|
}
|
||||||
|
|
||||||
public struct Capacity: Codable, Equatable, Sendable {
|
public struct CapacityContainer: Codable, Equatable, Sendable {
|
||||||
|
|
||||||
public let outdoorTemperature: Int
|
public let outdoorTemperature: Int
|
||||||
public let totalCapacity: Int
|
public let totalCapacity: Int
|
||||||
@@ -174,13 +174,13 @@ public enum CoolingInterpolation {
|
|||||||
public struct CapacityContainer: Codable, Equatable, Sendable {
|
public struct CapacityContainer: Codable, Equatable, Sendable {
|
||||||
|
|
||||||
public let outdoorTemperature: Int
|
public let outdoorTemperature: Int
|
||||||
public let aboveDewPoint: Models.Capacity.ManufacturersContainer
|
public let aboveDewPoint: Capacity.ManufacturersContainer
|
||||||
public let belowDewPoint: Models.Capacity.ManufacturersContainer
|
public let belowDewPoint: Capacity.ManufacturersContainer
|
||||||
|
|
||||||
public init(
|
public init(
|
||||||
outdoorTemperature: Int,
|
outdoorTemperature: Int,
|
||||||
aboveDewPoint: Models.Capacity.ManufacturersContainer,
|
aboveDewPoint: Capacity.ManufacturersContainer,
|
||||||
belowDewPoint: Models.Capacity.ManufacturersContainer
|
belowDewPoint: Capacity.ManufacturersContainer
|
||||||
) {
|
) {
|
||||||
self.outdoorTemperature = outdoorTemperature
|
self.outdoorTemperature = outdoorTemperature
|
||||||
self.aboveDewPoint = aboveDewPoint
|
self.aboveDewPoint = aboveDewPoint
|
||||||
|
|||||||
@@ -37,7 +37,6 @@ public enum Capacity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Remove.
|
|
||||||
public struct ManufacturersCooling: Codable, Equatable, Sendable {
|
public struct ManufacturersCooling: Codable, Equatable, Sendable {
|
||||||
|
|
||||||
public let airflow: Int
|
public let airflow: Int
|
||||||
|
|||||||
47
Sources/Models/HeatPumpHeatingInterpolation.swift
Normal file
47
Sources/Models/HeatPumpHeatingInterpolation.swift
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
public enum HeatPumpHeatingInterpolation {
|
||||||
|
public struct Request: Codable, Equatable, Sendable {
|
||||||
|
|
||||||
|
public let elevation: Int?
|
||||||
|
public let winterDesignTemperature: Int
|
||||||
|
public let heatLoss: Int
|
||||||
|
public let climateType: SystemType.ClimateType
|
||||||
|
public let capacity: Capacity.HeatPumpHeating
|
||||||
|
|
||||||
|
public init(
|
||||||
|
elevation: Int? = nil,
|
||||||
|
winterDesignTemperature: Int,
|
||||||
|
heatLoss: Int,
|
||||||
|
climateType: SystemType.ClimateType,
|
||||||
|
capacity: Capacity.HeatPumpHeating
|
||||||
|
) {
|
||||||
|
self.elevation = elevation
|
||||||
|
self.winterDesignTemperature = winterDesignTemperature
|
||||||
|
self.heatLoss = heatLoss
|
||||||
|
self.climateType = climateType
|
||||||
|
self.capacity = capacity
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct Response: Codable, Equatable, Sendable {
|
||||||
|
|
||||||
|
public let altitudeAdjustmentMultiplier: Double?
|
||||||
|
public let balancePointTemperature: Int
|
||||||
|
public let capacityAtDesign: Int
|
||||||
|
public let finalCapacity: Capacity.HeatPumpHeating
|
||||||
|
public let supplementalHeatRequired: Int
|
||||||
|
|
||||||
|
public init(
|
||||||
|
altitudeAdjustmentMultiplier: Double? = nil,
|
||||||
|
balancePointTemperature: Int,
|
||||||
|
capacityAtDesign: Int,
|
||||||
|
finalCapacity: Capacity.HeatPumpHeating,
|
||||||
|
supplementalHeatRequired: Int
|
||||||
|
) {
|
||||||
|
self.altitudeAdjustmentMultiplier = altitudeAdjustmentMultiplier
|
||||||
|
self.balancePointTemperature = balancePointTemperature
|
||||||
|
self.capacityAtDesign = capacityAtDesign
|
||||||
|
self.finalCapacity = finalCapacity
|
||||||
|
self.supplementalHeatRequired = supplementalHeatRequired
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -138,6 +138,27 @@ struct ManualSTests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
func heatPumpHeatingInterpolation() async throws {
|
||||||
|
try await withDependencies {
|
||||||
|
$0.manualS = .liveValue
|
||||||
|
} operation: {
|
||||||
|
@Dependency(\.manualS) var manualS
|
||||||
|
|
||||||
|
let response = try await manualS.heatPumpHeatingInterpolation(.init(
|
||||||
|
winterDesignTemperature: 5,
|
||||||
|
heatLoss: 49667,
|
||||||
|
climateType: .mildWinterOrLatentLoad,
|
||||||
|
capacity: .mock
|
||||||
|
))
|
||||||
|
|
||||||
|
#expect(response.finalCapacity == .mock)
|
||||||
|
#expect(response.capacityAtDesign == 11308)
|
||||||
|
#expect(response.balancePointTemperature == 38)
|
||||||
|
#expect(response.supplementalHeatRequired == 11)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
func balancePoint() async throws {
|
func balancePoint() async throws {
|
||||||
try await withDependencies {
|
try await withDependencies {
|
||||||
@@ -351,3 +372,7 @@ extension Capacity.Cooling {
|
|||||||
extension DesignInfo.Summer {
|
extension DesignInfo.Summer {
|
||||||
static let mock = Self(outdoorTemperature: 90, indoorTemperature: 75, indoorHumidity: 50)
|
static let mock = Self(outdoorTemperature: 90, indoorTemperature: 75, indoorHumidity: 50)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension Capacity.HeatPumpHeating {
|
||||||
|
static let mock = Self(at47: 24600, at17: 15100)
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user