Files
swift-estimated-pressures-core/Sources/SharedModels/FlaggedEquipmentMeasurement.swift
2024-05-24 16:44:41 -04:00

226 lines
6.4 KiB
Swift

import Foundation
// TODO: Needs updated for when forms are using `minmal` values.
public struct FlaggedEquipmentMeasurement: Equatable {
public var airflow: Flagged
public var coilPressureDrop: Flagged
public var externalStaticPressure: Flagged
public var filterPressureDrop: Flagged
public var returnPlenumPressure: Flagged
public var supplyPlenumPressure: Flagged
public init(
airflow: Flagged,
coilPressureDrop: Flagged,
externalStaticPressure: Flagged,
filterPressureDrop: Flagged,
returnPlenumPressure: Flagged,
supplyPlenumPressure: Flagged
) {
self.airflow = airflow
self.coilPressureDrop = coilPressureDrop
self.externalStaticPressure = externalStaticPressure
self.filterPressureDrop = filterPressureDrop
self.returnPlenumPressure = returnPlenumPressure
self.supplyPlenumPressure = supplyPlenumPressure
}
public init(
budgets: BudgetedPercentEnvelope,
measurement: EquipmentMeasurement,
ratedPressures: RatedStaticPressures,
tons: CoolingCapacity?
) {
switch measurement {
case let .airHandler(airHandler):
self = .airHandler(
budgets: budgets,
measurement: airHandler,
ratedPressures: ratedPressures,
tons: tons
)
case let .furnaceAndCoil(furnaceAndCoil):
self = .furnaceAndCoil(
budgets: budgets,
measurement: furnaceAndCoil,
ratedPressures: ratedPressures,
tons: tons
)
}
}
public static func airHandler(
budgets: BudgetedPercentEnvelope,
measurement: EquipmentMeasurement.AirHandler,
ratedPressures: RatedStaticPressures,
tons: CoolingCapacity?
) -> Self {
.init(
airflow: checkAirflow(value: measurement.airflow, tons: tons),
coilPressureDrop: .init(
wrappedValue: (measurement.$postCoilPressure.positiveValue - measurement.$postFilterPressure.positiveValue) ?? 0,
.result(.good())
),
externalStaticPressure: checkExternalStaticPressure(
value: measurement.externalStaticPressure,
ratedPressures: ratedPressures
),
filterPressureDrop: .init(
value: measurement.$postFilterPressure.positiveValue - measurement.$returnPlenumPressure.positiveValue,
budget: budgets.filterBudget,
ratedPressures: ratedPressures
),
returnPlenumPressure: .init(
value: measurement.$returnPlenumPressure.positiveValue,
budget: budgets.returnPlenumBudget,
ratedPressures: ratedPressures
),
supplyPlenumPressure: .init(
value: measurement.$supplyPlenumPressure.positiveValue ?? 0,
budget: budgets.supplyPlenumBudget,
ratedPressures: ratedPressures
)
)
}
public static func furnaceAndCoil(
budgets: BudgetedPercentEnvelope,
measurement: EquipmentMeasurement.FurnaceAndCoil,
ratedPressures: RatedStaticPressures,
tons: CoolingCapacity?
) -> Self {
.init(
airflow: checkAirflow(value: measurement.airflow, tons: tons),
coilPressureDrop: .init(
value: measurement.$preCoilPressure.positiveValue - measurement.$supplyPlenumPressure.positiveValue,
budget: budgets.coilBudget,
ratedPressures: ratedPressures
),
externalStaticPressure: checkExternalStaticPressure(
value: measurement.externalStaticPressure,
ratedPressures: ratedPressures
),
filterPressureDrop: .init(
value: measurement.$postFilterPressure.positiveValue - measurement.$returnPlenumPressure.positiveValue,
budget: budgets.filterBudget,
ratedPressures: ratedPressures,
ignoreMinimum: true
),
returnPlenumPressure: .init(
value: measurement.$returnPlenumPressure.positiveValue,
budget: budgets.returnPlenumBudget,
ratedPressures: ratedPressures
),
supplyPlenumPressure: .init(
value: measurement.$supplyPlenumPressure.positiveValue,
budget: budgets.supplyPlenumBudget,
ratedPressures: ratedPressures
)
)
}
}
// MARK: - Key
extension FlaggedEquipmentMeasurement {
// NOTE: These need to be kept in display order.
public enum Key: Equatable, CaseIterable {
case returnPlenum
case filterDrop
case coilDrop
case supplyPlenum
case staticPressure
case airflow
public var title: String {
switch self {
case .returnPlenum:
return "Return Plenum"
case .filterDrop:
return "Filter Pressure Drop"
case .coilDrop:
return "Coil Pressure Drop"
case .supplyPlenum:
return "Supply Plenum"
case .staticPressure:
return "External Static Pressure"
case .airflow:
return "System Airflow"
}
}
public var flaggedKeyPath: KeyPath<FlaggedEquipmentMeasurement, Flagged> {
switch self {
case .returnPlenum:
return \.returnPlenumPressure
case .filterDrop:
return \.filterPressureDrop
case .coilDrop:
return \.coilPressureDrop
case .supplyPlenum:
return \.supplyPlenumPressure
case .staticPressure:
return \.externalStaticPressure
case .airflow:
return \.airflow
}
}
}
}
// MARK: - Helpers
fileprivate extension Flagged {
init(
value: Double,
budget: Percentage,
ratedPressures: RatedStaticPressures,
ignoreMinimum: Bool = false
) {
let minimum = ignoreMinimum ? 0 : ratedPressures.minimum * budget.fraction
let maximum = ratedPressures.maximum * budget.fraction
let rated = ratedPressures.rated * budget.fraction
self.init(
wrappedValue: value,
.using(maximum: maximum, minimum: minimum, rated: rated)
)
}
init(
value: Double?,
budget: Percentage,
ratedPressures: RatedStaticPressures,
ignoreMinimum: Bool = false
) {
guard let value else {
self = .error(message: "Value is not set.")
return
}
self.init(
value: value,
budget: budget,
ratedPressures: ratedPressures,
ignoreMinimum: ignoreMinimum
)
}
}
fileprivate func checkExternalStaticPressure(
value: Double,
ratedPressures: RatedStaticPressures
) -> Flagged {
.init(
wrappedValue: value,
.rated(ratedPressures)
)
}
fileprivate func checkAirflow(
value: Double?,
tons: CoolingCapacity?
) -> Flagged {
guard let value, let tons else {
return .init(wrappedValue: value ?? 0, .result(.good()))
}
return .init(wrappedValue: value, .airflow(tons: tons))
}